diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..894437f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+pnpm-lock.ymal
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-lock.yaml
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..6a521b2
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,11 @@
+{
+ "cSpell.words": [
+ "aldeen",
+ "Datepicker",
+ "formik",
+ "Karim",
+ "queryqlent",
+ "szhsin",
+ "Viewelement"
+ ]
+}
\ No newline at end of file
diff --git a/db.json b/db.json
new file mode 100644
index 0000000..7d19fac
--- /dev/null
+++ b/db.json
@@ -0,0 +1,76 @@
+{
+ "example": [
+ {
+ "id": 1,
+ "name": "ibrahim",
+ "email": "ibrahim@gmail.com"
+ },
+ {
+ "id": 2,
+ "name": "gregr",
+ "email": "ibrahimgmail.com"
+ },
+ {
+ "id": 3,
+ "name": "mhmad",
+ "email": "mhmad@gmial.com"
+ },
+ {
+ "id": 4,
+ "name": "soso",
+ "email": "soso@gmail.com"
+ },
+ {
+ "id": 5,
+ "name": "few",
+ "email": "jfpwrej"
+ },
+ {
+ "id": 6,
+ "name": "sos",
+ "email": "fdwf"
+ },
+ {
+ "id": 7,
+ "name": "sos",
+ "email": "fdwf"
+ },
+ {
+ "id": 8,
+ "name": "sos",
+ "email": "fdwf"
+ }
+ ],
+ "test2":[
+
+
+ {
+ "id":1,
+ "email":"admin@adamin.com"
+ }
+ ,
+ {
+ "id":1,
+ "email":"admin@adamin.com"
+ }
+ ,
+ {
+ "id":1,
+ "email":"admin@adamin.com"
+ }
+
+ , {
+ "id":1,
+ "email":"admin@adamin.com"
+ }
+
+ ],
+ "users": [
+ {
+ "id": 1,
+ "email": "admin@adamin.com",
+ "password": "password",
+ "token": "token"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..6986b43
--- /dev/null
+++ b/package.json
@@ -0,0 +1,109 @@
+{
+ "name": "my-app",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@ant-design/icons": "^4.8.3",
+ "@emotion/styled": "^11.11.0",
+ "@mui/icons-material": "^5.14.19",
+ "@mui/x-charts": "^6.19.4",
+ "@react-google-maps/api": "^2.19.2",
+ "@szhsin/react-menu": "github:szhsin/react-menu",
+ "@testing-library/jest-dom": "^5.17.0",
+ "@testing-library/react": "^13.4.0",
+ "@testing-library/user-event": "^13.5.0",
+ "@tinymce/tinymce-react": "^4.3.2",
+ "@types/jest": "^27.5.2",
+ "@types/node": "^16.18.60",
+ "@types/react": "^18.2.33",
+ "@types/react-dom": "^18.2.14",
+ "@types/socket.io-client": "^3.0.0",
+ "@wojtekmaj/react-daterange-picker": "^5.4.4",
+ "antd": "^5.12.1",
+ "apexcharts": "^3.44.2",
+ "axios": "^1.6.0",
+ "bootstrap": "^5.3.2",
+ "chart.js": "^4.4.0",
+ "dayjs": "^1.11.10",
+ "formik": "^2.4.5",
+ "google-map-react": "^2.2.1",
+ "history": "^5.3.0",
+ "i18next": "^23.6.0",
+ "i18next-browser-languagedetector": "^7.1.0",
+ "json-server": "^0.17.4",
+ "leaflet": "^1.9.4",
+ "moment": "^2.30.1",
+ "prop-types": "^15.8.1",
+ "react": "^18.2.0",
+ "react-apexcharts": "^1.4.1",
+ "react-bootstrap": "^2.9.1",
+ "react-bootstrap-sweetalert": "^5.2.0",
+ "react-chartjs-2": "^5.2.0",
+ "react-confirm-alert": "^3.0.6",
+ "react-data-table-component": "^7.5.4",
+ "react-dom": "^18.2.0",
+ "react-feather": "^2.0.10",
+ "react-i18next": "^13.3.1",
+ "react-icons": "^4.11.0",
+ "react-input-range": "^1.3.0",
+ "react-leaflet": "^4.2.1",
+ "react-number-format": "^5.3.4",
+ "react-player": "^2.16.0",
+ "react-query": "^3.39.3",
+ "react-redux": "^8.1.3",
+ "react-router-dom": "^6.18.0",
+ "react-scripts": "5.0.1",
+ "react-select": "^5.7.7",
+ "react-simple-star-rating": "^5.1.7",
+ "react-switch": "^7.0.0",
+ "react-tabs": "^6.0.2",
+ "react-toastify": "^9.1.3",
+ "react-toggle": "^4.1.3",
+ "reactstrap": "^9.2.0",
+ "redux": "^4.2.1",
+ "sass": "^1.69.5",
+ "socket.io-client": "^4.7.2",
+ "styled-components": "5.3.3",
+ "ts-xlsx": "^0.0.11",
+ "typescript": "^4.9.5",
+ "web-vitals": "^2.1.4",
+ "xlsx": "^0.18.5",
+ "yup": "^1.3.2",
+ "zustand": "^4.4.5"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject",
+ "g:api": "node src/Extensions/FileGenerator/generateApi.js",
+ "g:column": "node src/Extensions/FileGenerator/generateColumn.js",
+ "g:formutil": "node src/Extensions/FileGenerator/generateformUtils.js",
+ "g:page": "node src/Extensions/FileGenerator/generatePage.js",
+ "g:dashboard": "node src/Extensions/FileGenerator/generateDashboard.js ",
+ "g:modal:add": "node src/Extensions/FileGenerator/generateEditModal.js ",
+ "g:model:edit": "node src/Extensions/FileGenerator/generateEditModal.js "
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ },
+ "devDependencies": {
+ "@types/leaflet": "^1.9.12",
+ "@types/react-toggle": "^4.0.5"
+ }
+}
diff --git a/public/Layout/LoginBg.jpg b/public/Layout/LoginBg.jpg
new file mode 100644
index 0000000..fc3a090
Binary files /dev/null and b/public/Layout/LoginBg.jpg differ
diff --git a/public/Logo.png b/public/Logo.png
new file mode 100644
index 0000000..2c0068f
Binary files /dev/null and b/public/Logo.png differ
diff --git a/public/Logo_2.png b/public/Logo_2.png
new file mode 100644
index 0000000..bdd8276
Binary files /dev/null and b/public/Logo_2.png differ
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..70b45ee
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ E-Menu - App
+
+
+
+
+
+
diff --git a/public/language/ar.svg b/public/language/ar.svg
new file mode 100644
index 0000000..c409129
--- /dev/null
+++ b/public/language/ar.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/language/de.svg b/public/language/de.svg
new file mode 100644
index 0000000..543a1bc
--- /dev/null
+++ b/public/language/de.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/language/en.svg b/public/language/en.svg
new file mode 100644
index 0000000..b1db6ff
--- /dev/null
+++ b/public/language/en.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/manifest.json b/public/manifest.json
new file mode 100644
index 0000000..080d6c7
--- /dev/null
+++ b/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..e9e57dc
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/public/test.mp4 b/public/test.mp4
new file mode 100644
index 0000000..ed139d6
Binary files /dev/null and b/public/test.mp4 differ
diff --git a/src/App.tsx b/src/App.tsx
new file mode 100644
index 0000000..722fd7d
--- /dev/null
+++ b/src/App.tsx
@@ -0,0 +1,69 @@
+import { Fragment, lazy, Suspense } from 'react';
+import { Route, Routes } from 'react-router-dom'
+import Loading from './Components/Utils/Loading/Loading';
+import { RoutesLinks } from './Routes';
+import Layout from './Layout/app/Layout';
+import Auth from './Pages/Auth/Page';
+const Page404 = lazy(() => import("./Layout/app/NotFoundPage"))
+
+const App = () => {
+
+
+ return (
+
+ {/* 404 Page */}
+ }> } />
+ {/* Login Page */}
+ }> } />
+
+ {/* route not in navigation */}
+
+
+ {/* All Routes */}
+ {RoutesLinks?.map((item: any, index: number) => (
+
+
+
+
+ if(item?.element){
+ } >
+
+ {item?.element ?? "Please Add Element Props in Routes"}
+
+
+ }
+ />
+ }else{
+ item?.children?.map((item:any)=>{
+ return(
+ } >
+
+ {item?.element ?? "Please Add Element Props in Routes"}
+
+
+ }
+ />
+ )
+ })
+
+ }
+
+
+
+ ))
+ }
+
+
+
+
+ )
+}
+
+export default App
\ No newline at end of file
diff --git a/src/Components/Columns/ColumnsImage.tsx b/src/Components/Columns/ColumnsImage.tsx
new file mode 100644
index 0000000..815ed9c
--- /dev/null
+++ b/src/Components/Columns/ColumnsImage.tsx
@@ -0,0 +1,85 @@
+import {
+ DownloadOutlined,
+ RotateLeftOutlined,
+ RotateRightOutlined,
+ SwapOutlined,
+ ZoomInOutlined,
+ ZoomOutOutlined,
+} from '@ant-design/icons';
+import React from 'react';
+import { Image, Space } from 'antd';
+import { ImageBaseURL } from '../../api/config';
+import useImageError from '../../Hooks/useImageError';
+
+
+const ColumnsImage= ({src}:any) => {
+ const ErrorImage = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/65/No-Image-Placeholder.svg/832px-No-Image-Placeholder.svg.png"
+
+ const imageUrl = ImageBaseURL + src || ErrorImage;
+
+ const handleError = useImageError;
+ // or you can download flipped and rotated image
+ // https://codesandbox.io/s/zi-ding-yi-gong-ju-lan-antd-5-7-0-forked-c9jvmp
+ const onDownload = () => {
+ fetch(src)
+ .then((response) => response.blob())
+ .then((blob) => {
+ const url = URL.createObjectURL(new Blob([blob]));
+ const link = document.createElement('a');
+ link.href = url;
+ link.download = 'image.png';
+ document.body.appendChild(link);
+ link.click();
+ URL.revokeObjectURL(url);
+ link.remove();
+ });
+ };
+
+ return (
+ (
+
+
+
+
+
+
+
+
+
+ ),
+ }}
+ onError={handleError}
+
+ />
+ );
+};
+
+export default ColumnsImage;
+
+
+
+
+
+
+
+// {
+// name: t("image"),
+// center: "true",
+// cell: (row: any) => {
+// return (
+//
+// )
+// }
+// },
\ No newline at end of file
diff --git a/src/Components/Columns/ColumnsSwitch.tsx b/src/Components/Columns/ColumnsSwitch.tsx
new file mode 100644
index 0000000..1b155b4
--- /dev/null
+++ b/src/Components/Columns/ColumnsSwitch.tsx
@@ -0,0 +1,42 @@
+import { Switch } from 'antd'
+import React from 'react'
+import { CheckOutlined, CloseOutlined } from '@ant-design/icons';
+import { useFormikContext } from 'formik';
+export interface ColumnsSwitchProps {
+ name: string;
+ Front?: string;
+ Back?: string;
+ onChange?: (checked:any,event:any) => any;
+ icon?: boolean
+ Checked?:boolean
+
+}
+const ColumnsSwitch = (props: ColumnsSwitchProps) => {
+ const { name, Front, Back, icon, onChange } = props;
+ const formik = useFormikContext();
+ const onSwitchChange = (checked: boolean, event: Event) => {
+ // formik.setFieldValue("status", checked)
+
+
+
+ };
+ return (
+ : Front}
+ unCheckedChildren={icon ? : Back}
+ onChange={ (checked:any,event:any)=> onChange ? onChange(checked,event) : onSwitchChange(checked,event)}
+ />
+ )
+}
+
+export default ColumnsSwitch
+
+
+ColumnsSwitch.defaultProps = {
+ Front: "Front",
+ Back: "Back",
+ onChange: undefined,
+ icon: false,
+ Checked:false
+
+};
\ No newline at end of file
diff --git a/src/Components/Ui/Alert.tsx b/src/Components/Ui/Alert.tsx
new file mode 100644
index 0000000..c232160
--- /dev/null
+++ b/src/Components/Ui/Alert.tsx
@@ -0,0 +1,50 @@
+import React from "react";
+import { confirmAlert } from "react-confirm-alert";
+import SweetAlert from "react-bootstrap-sweetalert";
+import { useTranslation } from "react-i18next";
+
+export default function CustomConfirmAlert(options : any) {
+ confirmAlert({
+ customUI: ({ onClose }) => ,
+ });
+}
+
+type CustomUIProps ={
+ onClose :()=> void
+ options:{
+ title?:string
+ confirmBtnText:string
+ cancelBtnText:string
+ body:string
+ onConfirm:()=>void
+
+
+ }
+}
+function CustomUI({ onClose, options }:CustomUIProps) {
+
+
+ const [t] = useTranslation()
+ return (
+
+ {
+ options.onConfirm();
+ onClose();
+ }}
+ onCancel={onClose}
+
+ />
+
+
+ );
+}
diff --git a/src/Components/Ui/CheckboxesVuexy.tsx b/src/Components/Ui/CheckboxesVuexy.tsx
new file mode 100644
index 0000000..5bc635e
--- /dev/null
+++ b/src/Components/Ui/CheckboxesVuexy.tsx
@@ -0,0 +1,49 @@
+import React from 'react';
+
+interface CheckBoxesVuexyProps {
+ className?: string;
+ color: string;
+ defaultChecked?: boolean;
+ checked?: boolean;
+ value?: string;
+ disabled?: boolean;
+ onClick?: () => void;
+ onChange?: () => void;
+ size?: string;
+ icon: React.ReactNode;
+ label: string;
+}
+
+const CheckBoxesVuexy: React.FC = ({
+ className = '',
+ color,
+ defaultChecked,
+ checked,
+ value,
+ disabled,
+ onClick,
+ onChange,
+ size = 'md',
+ icon,
+ label,
+}) => {
+ return (
+
+
+
+ {icon}
+
+ {label}
+
+ );
+};
+
+export default CheckBoxesVuexy;
diff --git a/src/Components/Ui/FileInput.tsx b/src/Components/Ui/FileInput.tsx
new file mode 100644
index 0000000..94c5df0
--- /dev/null
+++ b/src/Components/Ui/FileInput.tsx
@@ -0,0 +1,27 @@
+import React from 'react'
+import 'bootstrap/dist/css/bootstrap.min.css';
+import { Input } from 'reactstrap';
+import { useFormikContext } from 'formik';
+
+type FileInputProps = {
+ name:string,
+ label:string,
+ accept:string,
+ onChange:any
+}
+function FileInput({name , accept="image/*" ,label , onChange} :FileInputProps) {
+
+
+ return (
+
+
+
+
+
+ )
+}
+
+export default FileInput
\ No newline at end of file
diff --git a/src/Components/Ui/HovarableImage.tsx b/src/Components/Ui/HovarableImage.tsx
new file mode 100644
index 0000000..c56b31c
--- /dev/null
+++ b/src/Components/Ui/HovarableImage.tsx
@@ -0,0 +1,37 @@
+import React from "react";
+import { Tooltip } from "reactstrap";
+
+const tooltipStyle = {
+ backgroundColor: "white",
+ border: "2px solid lightgrey",
+ maxWidth: "400px",
+};
+
+const HovarableImage = ({ id, src, imgPreviewProps = {}, ...props }:any) => {
+ const [isOpen, setIsOpen] = React.useState(false);
+ const ID = `image_hover_tooltip_${id}`;
+ const toggleTooltip = React.useCallback(() => setIsOpen((prev) => !prev), []);
+
+ return (
+
+

+
+
+
+
+ );
+};
+
+export default HovarableImage;
+
diff --git a/src/Components/Ui/ImagePreview.tsx b/src/Components/Ui/ImagePreview.tsx
new file mode 100644
index 0000000..04e2177
--- /dev/null
+++ b/src/Components/Ui/ImagePreview.tsx
@@ -0,0 +1,34 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+
+const ImagePreview = ({ preview, height = 200 }:any) => {
+ const [t] = useTranslation();
+
+ return (
+
+ {preview ? (
+

+ ) : (
+
{t("image_preview")}
+ )}
+
+ );
+};
+
+export default ImagePreview;
diff --git a/src/Components/Ui/LoadingButton.tsx b/src/Components/Ui/LoadingButton.tsx
new file mode 100644
index 0000000..248c486
--- /dev/null
+++ b/src/Components/Ui/LoadingButton.tsx
@@ -0,0 +1,13 @@
+import React from "react";
+import { Button, Spinner } from "reactstrap";
+
+const LoadingButton = ({ isLoading = false, ...props }) => {
+ return (
+
+ );
+};
+
+export { LoadingButton };
diff --git a/src/Components/Ui/LoadingSpinner.tsx b/src/Components/Ui/LoadingSpinner.tsx
new file mode 100644
index 0000000..efa5055
--- /dev/null
+++ b/src/Components/Ui/LoadingSpinner.tsx
@@ -0,0 +1,10 @@
+import { Spin } from 'antd'
+import React from 'react'
+
+function LoadingSpinner() {
+ return (
+
+ )
+}
+
+export default LoadingSpinner
\ No newline at end of file
diff --git a/src/Components/Ui/PasswordField/PasswordField.tsx b/src/Components/Ui/PasswordField/PasswordField.tsx
new file mode 100644
index 0000000..32489d7
--- /dev/null
+++ b/src/Components/Ui/PasswordField/PasswordField.tsx
@@ -0,0 +1,57 @@
+import React, { FC, useState } from "react";
+import { ErrorMessage, useField, Field } from "formik";
+import { FormGroup } from "reactstrap";
+// import PropTypes from "prop-types";
+import { Eye, EyeOff } from "react-feather";
+import "./index.css";
+
+interface PasswordFieldProps {
+ name: string;
+ label?: string;
+}
+
+const PasswordField: FC = ({ name, label, ...props }) => {
+ const [field, meta] = useField({ name, ...props });
+ const [showPassword, setShowPassword] = useState(false);
+ const EyeIcon = showPassword ? Eye : EyeOff;
+
+ const toggleShow = () => {
+ setShowPassword((prev) => !prev);
+ };
+
+ return (
+ <>
+ {label && }
+
+
+
+
+
+
+
+ >
+ );
+};
+
+// PasswordField.propTypes = {
+// name: PropTypes.string.isRequired,
+// };
+
+export { PasswordField };
\ No newline at end of file
diff --git a/src/Components/Ui/PasswordField/index.css b/src/Components/Ui/PasswordField/index.css
new file mode 100644
index 0000000..7a26d93
--- /dev/null
+++ b/src/Components/Ui/PasswordField/index.css
@@ -0,0 +1,10 @@
+.back-icon {
+ font-size: 18px;
+ margin: 0;
+ margin-right: 5px;
+}
+
+.back-btn {
+ padding-left: 0.8rem;
+ padding-right: 1rem;
+}
diff --git a/src/Components/Ui/ProgressBar.tsx b/src/Components/Ui/ProgressBar.tsx
new file mode 100644
index 0000000..146339f
--- /dev/null
+++ b/src/Components/Ui/ProgressBar.tsx
@@ -0,0 +1,24 @@
+import React from "react";
+import { Progress } from "reactstrap";
+
+const ProgressBar = ({ value,isLoading, isSuccess, isError }:any) => {
+
+
+ let color = "";
+ if (!isLoading && isSuccess) {
+ color = "success";
+ }
+ if (!isLoading && isError) {
+ color = "danger";
+ }
+ return (
+
+ );
+};
+
+
+export default ProgressBar;
diff --git a/src/Components/Ui/SelectField.tsx b/src/Components/Ui/SelectField.tsx
new file mode 100644
index 0000000..f794e31
--- /dev/null
+++ b/src/Components/Ui/SelectField.tsx
@@ -0,0 +1,29 @@
+import React from "react";
+import Select from "react-select";
+import { ValidatedField } from "./ValidatedField";
+import { useFormikContext } from "formik";
+
+const SelectField = ({ label, name, options, ...props }:any) => {
+ const formik = useFormikContext();
+
+ return (
+ opt.value === formik?.values[name]) || ""}
+ onChange={(opt:any) => formik.setFieldValue(name, opt.value)}
+ onBlur={() => formik.setFieldTouched(name)}
+ key={name}
+ {...props}
+ />
+ );
+};
+
+
+export default SelectField;
+
+
diff --git a/src/Components/Ui/StaticsCard/StaticCard.tsx b/src/Components/Ui/StaticsCard/StaticCard.tsx
new file mode 100644
index 0000000..bd5fddc
--- /dev/null
+++ b/src/Components/Ui/StaticsCard/StaticCard.tsx
@@ -0,0 +1,58 @@
+import React from "react";
+import { Card, CardBody } from "reactstrap";
+import { ChartTypeEnum } from "../../../enums/ChartTypeEnum";
+import { history } from "../../../ProviderContainer";
+import { useNavigate } from "react-router-dom";
+
+interface StatisticsCardProps {
+ className?: string;
+ iconLeft?: boolean;
+ icon: React.ReactNode;
+ count?: string;
+ CardTitle?: string;
+ CardContent?: string;
+ height?: number;
+ pathWhenClick :string ;
+
+}
+
+const StatisticsCard = (props :StatisticsCardProps) => {
+
+ const navigate = useNavigate()
+ const {
+ className,
+ iconLeft = false ,
+ icon,
+ count,
+ CardTitle,
+ CardContent,
+ pathWhenClick,
+ height,
+ ...rest
+ } = props;
+
+ return (
+ navigate(pathWhenClick )}>
+
+
+
+ {/*
{CardTitle}
*/}
+
{icon}
+
+
+
+ {/*
{count}
*/}
+
{CardContent}
+
+
+
+ );
+};
+
+export default StatisticsCard;
diff --git a/src/Components/Ui/StatusBadge.tsx b/src/Components/Ui/StatusBadge.tsx
new file mode 100644
index 0000000..1fb55e6
--- /dev/null
+++ b/src/Components/Ui/StatusBadge.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+import { Badge } from "reactstrap";
+
+const StatusBadge = ({ status }:any) => {
+ const [t] = useTranslation();
+
+ return (
+
+ {status ? t("active") : t("inacticve")}
+
+ );
+};
+
+
+
+export default StatusBadge;
diff --git a/src/Components/Ui/TableActions.tsx b/src/Components/Ui/TableActions.tsx
new file mode 100644
index 0000000..73c9563
--- /dev/null
+++ b/src/Components/Ui/TableActions.tsx
@@ -0,0 +1,38 @@
+import React , {ReactNode} from "react";
+import confirmAlert from "./Alert";
+import { FaEdit, FaTrash } from "react-icons/fa";
+
+type TableActionsProps = {
+ onDelete: () => any;
+ onEdit: () => void;
+ showEdit?: boolean;
+ showDelete?: boolean;
+ children?: ReactNode;
+};
+
+
+const TableActions = ({ onDelete , onEdit,showEdit=true,showDelete=true, children }:TableActionsProps) => {
+
+
+ return (
+
+ {showEdit && }
+ {showDelete && (
+
+ confirmAlert({
+ onConfirm: () => {
+ onDelete();
+
+ },
+ })
+ }
+ className="cursor-pointer"
+ size={20}
+ />
+ )}
+ {children}
+
+);
+};
+export default TableActions;
diff --git a/src/Components/Ui/ThreeSwitchState/TripleSwitch.tsx b/src/Components/Ui/ThreeSwitchState/TripleSwitch.tsx
new file mode 100644
index 0000000..c36ffbd
--- /dev/null
+++ b/src/Components/Ui/ThreeSwitchState/TripleSwitch.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import type { RadioChangeEvent } from 'antd';
+import { Radio } from 'antd';
+
+const onChange = (e: RadioChangeEvent) => {
+ console.log(`radio checked:${e.target.value}`);
+};
+
+const App: React.FC = () => (
+ <>
+
+
+
+ Hangzhou
+
+ Shanghai
+
+ Beijing
+ Chengdu
+
+
+
+ Hangzhou
+ Shanghai
+ Beijing
+ Chengdu
+
+ >
+);
+
+export default App;
diff --git a/src/Components/Ui/ToggleStatus.tsx b/src/Components/Ui/ToggleStatus.tsx
new file mode 100644
index 0000000..40df144
--- /dev/null
+++ b/src/Components/Ui/ToggleStatus.tsx
@@ -0,0 +1,39 @@
+import React from "react";
+import Toggle from "react-toggle";
+import "react-toggle/style.css";
+import StatusBadge from "./StatusBadge";
+import { useTranslation } from "react-i18next";
+
+interface ToggleStatusProps {
+
+}
+export const ToggleStatus = ({ object, handleSwitch, toggleMutation, ...props }:any) => {
+ const [t] = useTranslation();
+
+ // const handleSwitch = () => {
+ // toggleMutation.mutate({
+ // id: object.id,
+ // new_status: !object.is_active,
+ // });
+ // };
+
+ return (
+ <>
+
+
+ {object.is_active ? t("active") : t("inactive")}
+
+
+
+ >
+ );
+};
diff --git a/src/Components/Ui/ValidatedField.tsx b/src/Components/Ui/ValidatedField.tsx
new file mode 100644
index 0000000..c2bd089
--- /dev/null
+++ b/src/Components/Ui/ValidatedField.tsx
@@ -0,0 +1,64 @@
+import React from "react";
+import { ErrorMessage, useField, Field } from "formik";
+import { FormGroup } from "reactstrap";
+import { useTranslation } from "react-i18next";
+
+const ValidatedField = ({
+ name,
+ label,
+ CustomField,
+ icon: Icon,
+ optional,
+ labelIcon = null,
+ formProps,
+ isRequired,
+
+ ...props
+}:any) => {
+
+ const [field, meta] = useField({ name, ...props });
+ const [t] = useTranslation();
+
+ let Wrapper = Field;
+
+ if (CustomField) {
+ Wrapper = CustomField;
+ }
+ const fieldProps = props.type === "file" ? {} : { ...field };
+
+ return (
+ <>
+ {label && (
+
+ )}
+
+
+ {Icon && (
+
+
+
+ )}
+
+ {(msg) => {t(msg)}}
+
+
+ >
+ );
+};
+
+
+export { ValidatedField };
diff --git a/src/Components/Ui/index.tsx b/src/Components/Ui/index.tsx
new file mode 100644
index 0000000..ae6a6f0
--- /dev/null
+++ b/src/Components/Ui/index.tsx
@@ -0,0 +1,17 @@
+import Checkbox from './CheckboxesVuexy'
+import ImagePreview from './ImagePreview'
+import SelectField from './SelectField'
+import { useImagePreview } from './useImagePreview'
+import {ValidatedField} from './ValidatedField'
+import StatusBadge from './StatusBadge'
+import HovarableImage from './HovarableImage'
+
+export {
+ Checkbox,
+ ImagePreview,
+ SelectField,
+ useImagePreview,
+ ValidatedField,
+ StatusBadge,
+ HovarableImage
+}
\ No newline at end of file
diff --git a/src/Components/Ui/tables/Actions.tsx b/src/Components/Ui/tables/Actions.tsx
new file mode 100644
index 0000000..f78e1ad
--- /dev/null
+++ b/src/Components/Ui/tables/Actions.tsx
@@ -0,0 +1,58 @@
+import React , {ReactNode} from "react";
+import { FaEdit, FaEye, FaTrash } from "react-icons/fa";
+import CustomConfirmAlert from "../Alert";
+import { usePageState } from "../../../lib/state mangment/LayoutPagestate";
+
+type TableActionsProps = {
+ onDelete?: () => any;
+ onEdit?: () => any;
+ onView?:() => any;
+ showView?: boolean;
+ showEdit?: boolean;
+ showDelete?: boolean;
+ children?: ReactNode;
+ objectToEdit:any
+ className?:string
+
+};
+
+
+const TableActions = ({ onDelete=()=>{} , objectToEdit,onEdit=()=>{},onView,showEdit=true,showDelete=true,showView=true,children,className }:TableActionsProps) => {
+// const TableActions = ({ onDelete=()=>{} , objectToEdit,onEdit=()=>{},onView,showEdit=true,showDelete=true,showView=true,children }:TableActionsProps) => {
+
+ // console.log(objectToEdit);
+
+ const {setObjectToEdit , setIsOpenEditModel} = usePageState()
+ return (
+
+ {showEdit && {
+ setObjectToEdit(objectToEdit)
+ setIsOpenEditModel()
+ onEdit()
+
+ }} className="cursor-pointer m-2" size={20} />}
+ {showView && }
+
+
+ {showDelete && (
+
+ CustomConfirmAlert({
+ onConfirm: () => {
+
+
+ onDelete();
+
+ },
+ })
+ }
+ className="cursor-pointer"
+ size={20}
+ />
+ )}
+
+ {children}
+
+);
+};
+export default TableActions;
diff --git a/src/Components/Ui/tables/ConfirmAlert.tsx b/src/Components/Ui/tables/ConfirmAlert.tsx
new file mode 100644
index 0000000..bb99f66
--- /dev/null
+++ b/src/Components/Ui/tables/ConfirmAlert.tsx
@@ -0,0 +1,40 @@
+import React from "react";
+import { confirmAlert } from "react-confirm-alert";
+import SweetAlert from "react-bootstrap-sweetalert";
+
+interface CustomUIProps {
+ onClose: () => void;
+ options: {
+ title?: string;
+ confirmBtnText?: string;
+ cancelBtnText?: string;
+ onConfirm: () => void;
+ body?: string;
+ };
+}
+
+export default function CustomConfirmAlert(options: any) {
+ confirmAlert({
+ customUI: ({ onClose }) => ,
+ });
+}
+
+function CustomUI({ onClose, options }: CustomUIProps) {
+ const sweetAlertProps: any = {
+ title: options.title || `DELETE, Are you sure?`,
+ warning: true,
+ show: true,
+ showCancel: true,
+ reverseButtons: true,
+ cancelBtnBsStyle: "danger",
+ confirmBtnText: options.confirmBtnText || "Yes, delete it!",
+ cancelBtnText: options.cancelBtnText || "Cancel",
+ onConfirm: () => {
+ options.onConfirm();
+ onClose();
+ },
+ onCancel: onClose,
+ };
+
+ return {options.body || "You won't be able to revert this!"};
+}
diff --git a/src/Components/Ui/useImagePreview.tsx b/src/Components/Ui/useImagePreview.tsx
new file mode 100644
index 0000000..818c68e
--- /dev/null
+++ b/src/Components/Ui/useImagePreview.tsx
@@ -0,0 +1,24 @@
+import { useState, useEffect } from "react";
+
+export const useImagePreview = (defaultValue:any = null) => {
+ const [preview, setPreview] = useState(defaultValue || null);
+
+ useEffect(() => {
+ return () => {
+ URL.revokeObjectURL(preview);
+
+ };
+ }, [preview]);
+
+ const handleImageChange = (event:any) => {
+
+ setPreview(URL.createObjectURL(event.target.files[0]));
+
+ };
+
+ return {
+ preview,
+ handleImageChange,
+ setPreview,
+ };
+};
diff --git a/src/Components/Utils/BlockModal.tsx b/src/Components/Utils/BlockModal.tsx
new file mode 100644
index 0000000..d6c47f0
--- /dev/null
+++ b/src/Components/Utils/BlockModal.tsx
@@ -0,0 +1,62 @@
+
+import React, { useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
+import { BsExclamationCircle } from 'react-icons/bs';
+import { Button, Card, CardBody, Input, Label, Modal, ModalHeader } from 'reactstrap';
+import { useCommonModelState } from '../../lib/state mangment/driver&customer/ModelState';
+import { LoadingButton } from '../Ui/LoadingButton';
+
+interface BlockModelProps {
+ Mutation:any,
+ type :'customer' |'driver'
+}
+
+const BlockModel: React.FC = ({Mutation ,type}) => {
+ const {t} = useTranslation();
+ const key_to_api = type == t('customer') ? t('customer_id') : t("driver_id")
+
+ const {isOpenBlock:isOpen , objectID , setIsopenBlock:setIsOpen} = useCommonModelState()
+
+ const handleSubmit = () => {
+ const blockInput = document.getElementById('block_input') as HTMLInputElement;
+ if (blockInput) {
+ Mutation.mutate({ [key_to_api]: objectID, block_timer: blockInput.value });
+ }
+ };
+
+ useEffect(() => {
+ if (Mutation.isSuccess) {
+ setIsOpen();
+ }
+ }, [Mutation.isSuccess, setIsOpen]);
+
+ return (
+
+ setIsOpen()}>
+ {t("al")}{type}{t('_block_page')}
+
+
+
+
+
{t('blocking_')}{type}
+
+
+
+
+
+
+
+ {t('add_block_for_')}{type}
+
+
+
+
+
+
+
+ );
+};
+
+export default BlockModel;
diff --git a/src/Components/Utils/GiftModal.tsx b/src/Components/Utils/GiftModal.tsx
new file mode 100644
index 0000000..bbd8d3e
--- /dev/null
+++ b/src/Components/Utils/GiftModal.tsx
@@ -0,0 +1,63 @@
+import React, { useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
+import { BsExclamationCircle } from 'react-icons/bs';
+import { Button, Card, CardBody, Col, Input, Label, Modal, ModalHeader, Row } from 'reactstrap';
+import { useCommonModelState } from '../../lib/state mangment/driver&customer/ModelState';
+import { LoadingButton } from '../Ui/LoadingButton';
+
+
+interface GiftModalProps {
+ Mutation:any,
+ type :'customer' |'driver'
+}
+
+const GiftModal: React.FC = ({Mutation ,type }) => {
+ const {t} = useTranslation();
+
+ const {isOpenGift:isOpen , objectID , setIsopenGift:setIsOpen} = useCommonModelState()
+
+ useEffect(() => {
+ if (Mutation.isSuccess) {
+ setIsOpen();
+ }
+ }, [Mutation.isSuccess, setIsOpen]);
+
+ const handleGift = () => {
+ const enterCodesInput = document.getElementById('enter_codes') as HTMLInputElement;
+ if (enterCodesInput && enterCodesInput.value) {
+ Mutation.mutate({ type, id: objectID, value: enterCodesInput.value });
+ }
+ };
+
+ return (
+
+ setIsOpen()}>
+ {t("al")}{type} {t('_gift_page')}
+
+
+
+
+
+
+
+
+
+
+ {t('give')}
+
+
+
+
+
+
+
+ );
+};
+
+export default GiftModal;
diff --git a/src/Components/Utils/Loading/Loading.scss b/src/Components/Utils/Loading/Loading.scss
new file mode 100644
index 0000000..9ffb658
--- /dev/null
+++ b/src/Components/Utils/Loading/Loading.scss
@@ -0,0 +1,93 @@
+.Loading{
+
+ .wrapper {
+ width: 200px;
+ height: 60px;
+ position: relative;
+ left: 40%;
+ z-index: 1;
+ }
+
+ .circle {
+ width: 20px;
+ height: 20px;
+ position: absolute;
+ border-radius: 50%;
+ background-color: var(--primary);
+ left: 15%;
+ transform-origin: 50%;
+ animation: circle7124 .5s alternate infinite ease;
+ }
+
+ @keyframes circle7124 {
+ 0% {
+ top: 60px;
+ height: 5px;
+ border-radius: 50px 50px 25px 25px;
+ transform: scaleX(1.7);
+ }
+
+ 40% {
+ height: 20px;
+ border-radius: 50%;
+ transform: scaleX(1);
+ }
+
+ 100% {
+ top: 0%;
+ }
+ }
+
+ .circle:nth-child(2) {
+ left: 45%;
+ animation-delay: .2s;
+ }
+
+ .circle:nth-child(3) {
+ left: auto;
+ right: 15%;
+ animation-delay: .3s;
+ }
+
+ .shadow {
+ width: 20px;
+ height: 4px;
+ border-radius: 50%;
+ background-color: rgba(0,0,0,0.9);
+ position: absolute;
+ top: 62px;
+ transform-origin: 50%;
+ z-index: -1;
+ left: 15%;
+ filter: blur(1px);
+ animation: shadow046 .5s alternate infinite ease;
+ }
+
+ @keyframes shadow046 {
+ 0% {
+ transform: scaleX(1.5);
+ }
+
+ 40% {
+ transform: scaleX(1);
+ opacity: .7;
+ }
+
+ 100% {
+ transform: scaleX(.2);
+ opacity: .4;
+ }
+ }
+
+ .shadow:nth-child(4) {
+ left: 45%;
+ animation-delay: .2s
+ }
+
+ .shadow:nth-child(5) {
+ left: auto;
+ right: 15%;
+ animation-delay: .3s;
+ }
+
+}
diff --git a/src/Components/Utils/Loading/Loading.tsx b/src/Components/Utils/Loading/Loading.tsx
new file mode 100644
index 0000000..19651b4
--- /dev/null
+++ b/src/Components/Utils/Loading/Loading.tsx
@@ -0,0 +1,19 @@
+import React from 'react'
+import './Loading.scss'
+const Loading = () => {
+
+ return (
+
+ )
+}
+
+export default Loading
\ No newline at end of file
diff --git a/src/Components/Utils/SearchBar/SearchBar.scss b/src/Components/Utils/SearchBar/SearchBar.scss
new file mode 100644
index 0000000..6834dcf
--- /dev/null
+++ b/src/Components/Utils/SearchBar/SearchBar.scss
@@ -0,0 +1,43 @@
+.SearchBar{
+ .group {
+ display: flex;
+ align-items: center;
+ position: relative;
+ max-width: 190px;
+ }
+
+ .input {
+ width: 100%;
+ height: 40px;
+ padding: 0 1rem;
+ padding-left: 2.5rem;
+ border-radius: 8px;
+ outline: none;
+ font-weight: 500;
+ background: var(--primary);
+ color: var(--bg);
+ border: none;
+ box-shadow: 2px 2px 7px 0 var(--primary);
+
+ }
+
+ .input::placeholder {
+ color: var(--bg);
+ }
+
+
+
+ .icon {
+ position: absolute;
+ left: 1rem;
+ fill: var(--bg);
+ width: 1rem;
+ height: 1rem;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/Components/Utils/SearchBar/SearchBar.tsx b/src/Components/Utils/SearchBar/SearchBar.tsx
new file mode 100644
index 0000000..f1f5cd2
--- /dev/null
+++ b/src/Components/Utils/SearchBar/SearchBar.tsx
@@ -0,0 +1,14 @@
+import React from 'react'
+import './SearchBar.scss'
+const SearchBar = () => {
+ return (
+
+ )
+}
+
+export default SearchBar
\ No newline at end of file
diff --git a/src/Components/Utils/Theme.tsx b/src/Components/Utils/Theme.tsx
new file mode 100644
index 0000000..7681ffd
--- /dev/null
+++ b/src/Components/Utils/Theme.tsx
@@ -0,0 +1,84 @@
+import { Menu, MenuItem, MenuButton } from '@szhsin/react-menu';
+import { useTranslation } from 'react-i18next';
+import { usePageState } from '../../lib/state mangment/LayoutPagestate';
+import { BsFillMoonStarsFill, BsFillSunFill, BsSunglasses } from 'react-icons/bs';
+
+
+let What_the_Theme = localStorage.getItem('theme') ?? "light";
+
+if (What_the_Theme === "dark") {
+
+ document.body.classList.add('dark')}
+ else if (What_the_Theme === "glass") {
+
+ document.body.classList.add('glass')
+ }
+
+
+
+
+export default function Theme() {
+ const {t} = useTranslation();
+
+ const {setThemChange} = usePageState()
+
+ const changeTheme = (newTheme : any) => {
+
+
+ if(newTheme === "dark"){
+ document.body.classList.remove('glass');
+ document.body.classList.add('dark');localStorage.setItem("theme", "dark");
+ What_the_Theme = "dark"
+ }
+ else if(newTheme === "light"){
+ document.body.classList.remove('glass');
+ document.body.classList.remove('dark');localStorage.setItem("theme", "light");
+ What_the_Theme = "light"
+
+ }
+ else if(newTheme === "glass"){
+ document.body.classList.remove('dark'); document.body.classList.add('glass'); localStorage.setItem("theme", "glass");
+ What_the_Theme = "glass"
+
+ }
+ setThemChange()
+ };
+ /// BsSunglasses BsFillSunFill BsFillMoonStarsFill
+
+
+ return (
+
+
+
+
+ );
+}
diff --git a/src/Components/Utils/Translate.tsx b/src/Components/Utils/Translate.tsx
new file mode 100644
index 0000000..a5aa816
--- /dev/null
+++ b/src/Components/Utils/Translate.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { Menu, Dropdown } from 'antd';
+import { useLanguage, useLanguageMenu } from '../../Hooks/useChangeLanguage';
+import i18next from 'i18next';
+import type { MenuProps } from 'antd';
+
+export default function Translate() {
+ const { changeLanguage } = useLanguage();
+ const { languageOptions } = useLanguageMenu();
+
+ const handleLanguageChange = (newLanguage:string) => {
+ changeLanguage(newLanguage);
+ };
+
+ const items : MenuProps['items'] = languageOptions.map((option:any,index:number) => ({
+ key: index,
+ label: (
+ handleLanguageChange(option.code)}>
+

+ {option.label}
+
+ )
+ }));
+
+
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/src/Components/Utils/UnBlockModal.tsx b/src/Components/Utils/UnBlockModal.tsx
new file mode 100644
index 0000000..cf3fac1
--- /dev/null
+++ b/src/Components/Utils/UnBlockModal.tsx
@@ -0,0 +1,60 @@
+
+import React, { useEffect } from 'react';
+import { BsExclamationCircle } from 'react-icons/bs';
+import { Button, Card, CardBody, Input, Label, Modal, ModalHeader } from 'reactstrap';
+import { useTranslation } from 'react-i18next';
+import { LoadingButton } from '../Ui/LoadingButton';
+import { useCommonModelState } from '../../lib/state mangment/driver&customer/ModelState';
+import { CiLock } from "react-icons/ci";
+
+interface UnBlockModalProps {
+
+ Mutation:any,
+ type :'customer' |'driver'
+}
+
+const UnBlockModal: React.FC = ({Mutation ,type }) => {
+ const {t} = useTranslation();
+
+ const key_to_api = type == t('customer') ? t('customer_id') : t("driver_id")
+
+ const {isOpenUnBlock:isOpen , objectID , setIsopenUnBlock:setIsopen} = useCommonModelState()
+
+ const handleSubmit = () => {
+ Mutation.mutate({ [key_to_api]: objectID });
+ };
+
+ useEffect(() => {
+ if (Mutation.isSuccess) {
+ setIsopen();
+ }
+ }, [Mutation.isSuccess, setIsopen]);
+
+ return (
+
+ setIsopen()}>
+ {t("al")}{type} {t('un_block_page')}
+
+
+
+
+
{t('un_blocking_')}{type}
+
+
+
+
+
+ {t('un_block_for_')}{type}
+
+
+
+
+
+
+
+ );
+};
+
+export default UnBlockModal;
diff --git a/src/Components/ValidationField/Ui/KarimSpinner.tsx b/src/Components/ValidationField/Ui/KarimSpinner.tsx
new file mode 100644
index 0000000..12206f9
--- /dev/null
+++ b/src/Components/ValidationField/Ui/KarimSpinner.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { Spin } from 'antd';
+
+interface Props {
+ loading: boolean;
+ children: React.ReactNode;
+ className?: string;
+}
+
+const KarimSpinner: React.FC = ({ loading, className, children }) => {
+ return (
+
+ {loading ?
: children}
+
+ );
+};
+
+export default KarimSpinner;
diff --git a/src/Components/ValidationField/Ui/SearchBar.scss b/src/Components/ValidationField/Ui/SearchBar.scss
new file mode 100644
index 0000000..2ddadd9
--- /dev/null
+++ b/src/Components/ValidationField/Ui/SearchBar.scss
@@ -0,0 +1,48 @@
+.SearchBar{
+ // margin-top: 20px;
+ .group {
+ display: flex;
+ align-items: center;
+ position: relative;
+ max-width: 350px;
+ width: 350px;
+
+ }
+
+ .input {
+ width: 100%;
+ height: 40px;
+ padding: 0 1rem;
+ padding-left: 2.5rem;
+ border-radius: 8px;
+ outline: none;
+ font-weight: 500;
+ background: var(--bg);
+ color: var(--text);
+ border: none;
+ box-shadow: 2px 2px 7px 0 var(--bg);
+
+ }
+
+ .input::placeholder {
+ color: var(--subtext);
+ opacity: .4;
+
+ }
+
+
+
+ .icon {
+ position: absolute;
+ left: 1rem;
+ fill: var(--subtext);
+ width: 1rem;
+ height: 1rem;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/Components/ValidationField/Ui/SearchBar.tsx b/src/Components/ValidationField/Ui/SearchBar.tsx
new file mode 100644
index 0000000..f70b289
--- /dev/null
+++ b/src/Components/ValidationField/Ui/SearchBar.tsx
@@ -0,0 +1,35 @@
+import React, { useState } from 'react'
+import './SearchBar.scss'
+import { useNavigate, useSearchParams } from 'react-router-dom';
+const SearchBar = () => {
+ const [searchQuery, setSearchQuery] = useState('');
+ const [searchParams] = useSearchParams()
+ const navigate = useNavigate();
+
+ const handleChange = (event:any) => {
+ const { value } = event.target;
+ setSearchQuery(value);
+ updateUrlParams(value);
+ };
+
+ const updateUrlParams = (value:any) => {
+ navigate(`?search=${value}`);
+
+
+ };
+
+ return (
+
+ )
+}
+
+export default SearchBar
\ No newline at end of file
diff --git a/src/Components/ValidationField/ValidationField.scss b/src/Components/ValidationField/ValidationField.scss
new file mode 100644
index 0000000..97e9f5e
--- /dev/null
+++ b/src/Components/ValidationField/ValidationField.scss
@@ -0,0 +1,78 @@
+.ValidationField{
+ >*{
+ width: 100%;
+ }
+ .text,.ant-form-item{
+ margin-bottom:7px !important;
+
+ }
+
+ >span{
+ margin-bottom: 0px !important;
+ &:focus-within{
+ border-color: var(--primary) ;
+ box-shadow: 0 0 0 1px var(--primary);
+ cursor: pointer;
+ }
+ &:has(.is-invalid){
+ border-color: red !important;
+
+ }
+ input{
+ color: var(--text);
+ background: var(--bg);
+ }
+
+input:-webkit-autofill,
+input:-webkit-autofill:hover,
+input:-webkit-autofill:focus,
+input:-webkit-autofill:active{
+ -webkit-box-shadow: 0 0 0 30px white inset !important;
+}
+ }
+}
+
+.ant-upload-select{
+ width: 100%;
+}
+.Checkboxs{
+ padding: 4%;
+}
+.SearchField{
+ button{
+ background: var(--primary);
+ }
+}
+.text{
+ color: var(--text);
+}
+
+input:disabled{
+ color: var(--text) !important;
+}
+
+.isError{
+ outline: red 1px solid;
+ color: red;
+}
+.Error_color{
+ color: red;
+
+}
+input:-webkit-autofill {
+ -webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
+}
+input:-webkit-autofill:focus {
+ -webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
+}
+
+/* Remove autofill background color on hover */
+input:-webkit-autofill:hover {
+ -webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
+}
+
+
+.ant-upload-list .ant-upload-list-item{
+ height:78px !important;
+ }
+
\ No newline at end of file
diff --git a/src/Components/ValidationField/ValidationField.tsx b/src/Components/ValidationField/ValidationField.tsx
new file mode 100644
index 0000000..6e25672
--- /dev/null
+++ b/src/Components/ValidationField/ValidationField.tsx
@@ -0,0 +1,34 @@
+import React from "react";
+import "./ValidationField.scss";
+import { Date, Time, File, DataRange, SelectField, Default, CheckboxField ,TextAreaField} from './View';
+import { ValidationFieldProps } from "./types";
+import MaltyFile from "./View/MaltyFile";
+import SearchField from "./View/SearchField";
+
+const ValidationField: React.FC = ({type , ...otherProps}) => {
+
+ switch (type) {
+ case 'Select':
+ return ;
+ case 'Search':
+ return ;
+ case "DataRange":
+ return ;
+ case "Date":
+ return ;
+ case "Time":
+ return ;
+ case "File":
+ return ;
+ case "MaltyFile":
+ return ;
+ case "Checkbox":
+ return ;
+ case "TextArea":
+ return ;
+ default:
+ return ;
+ }
+};
+
+export default React.memo(ValidationField);
diff --git a/src/Components/ValidationField/View/CheckboxField.tsx b/src/Components/ValidationField/View/CheckboxField.tsx
new file mode 100644
index 0000000..21c419e
--- /dev/null
+++ b/src/Components/ValidationField/View/CheckboxField.tsx
@@ -0,0 +1,36 @@
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+import { Checkbox, Form } from 'antd';
+
+const CheckboxField = ({ name, label, isDisabled, onChange,Group,className, props }: any) => {
+
+ const { t, formik,isError,errorMsg} = useFormField(name, props)
+ const CheckboxhandleChange = (value: any) => {
+ formik.setFieldValue(name, value?.target?.checked)
+
+ };
+ return (
+
+
+
+ {t(`${label ? label : name}`)}
+
+
+
+
+ )
+}
+
+export default CheckboxField
\ No newline at end of file
diff --git a/src/Components/ValidationField/View/DataRange.tsx b/src/Components/ValidationField/View/DataRange.tsx
new file mode 100644
index 0000000..742e6b5
--- /dev/null
+++ b/src/Components/ValidationField/View/DataRange.tsx
@@ -0,0 +1,44 @@
+import { Form, DatePicker } from 'antd'
+
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+
+const { RangePicker } = DatePicker;
+
+const DataRange = ({ name, label, Format, props, onChange, isDisabled, placeholder, className }: any) => {
+
+ const { errorMsg, isError, t, formik } = useFormField(name, props)
+ const onCalendarChange = (value: any) => {
+
+ formik.setFieldValue(name, value)
+
+ };
+ return (
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default DataRange
\ No newline at end of file
diff --git a/src/Components/ValidationField/View/Date.tsx b/src/Components/ValidationField/View/Date.tsx
new file mode 100644
index 0000000..dde451d
--- /dev/null
+++ b/src/Components/ValidationField/View/Date.tsx
@@ -0,0 +1,51 @@
+import { Form, DatePicker } from 'antd';
+import React from 'react';
+import useFormField from '../../../Hooks/useFormField';
+import dayjs from 'dayjs';
+
+const DateField = ({ name, label, picker = "date", isDisabled, props, onChange, placeholder, className, Format }: any) => {
+
+ const { errorMsg, isError, t, formik } = useFormField(name, props);
+
+ const onCalendarChange = (value: any) => {
+ formik.setFieldValue(name, value);
+ };
+
+ // Function to check if a date is valid
+ const isValidDate = (date: any) => {
+ return date && !isNaN(date.valueOf()) && dayjs(date).isValid();
+ };
+
+ // Set a default invalid date if the provided defaultValue is invalid
+ const getDefaultDate = () => {
+ const defaultValue = formik.values[name];
+ return isValidDate(defaultValue) ? defaultValue : null; // Set to null or any other default invalid date
+ };
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default DateField;
diff --git a/src/Components/ValidationField/View/Default.tsx b/src/Components/ValidationField/View/Default.tsx
new file mode 100644
index 0000000..1d0678d
--- /dev/null
+++ b/src/Components/ValidationField/View/Default.tsx
@@ -0,0 +1,36 @@
+import { Form, Input } from 'antd'
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+
+const Default = ({ name, label, placeholder, isDisabled, onChange, props,type }: any) => {
+ const { Field, formik, isError, errorMsg, t } = useFormField(name, props);
+
+
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default React.memo(Default);
+;
diff --git a/src/Components/ValidationField/View/File.tsx b/src/Components/ValidationField/View/File.tsx
new file mode 100644
index 0000000..f773f1b
--- /dev/null
+++ b/src/Components/ValidationField/View/File.tsx
@@ -0,0 +1,63 @@
+import { Button, Upload, UploadFile } from 'antd'
+import useFormField from '../../../Hooks/useFormField';
+import { UploadOutlined } from '@ant-design/icons';
+import { ImageBaseURL } from '../../../api/config';
+
+
+const File = ({ name, label, onChange, isDisabled,placholder,className,acceptedFileType, props }: any) => {
+ const { formik, t ,isError} = useFormField(name, props)
+ let FormikName = formik.values[name];
+ const imageUrl = formik.values[name] ? ImageBaseURL + FormikName : '';
+
+ const fileList: UploadFile[] = [
+
+ {
+ uid: '-1',
+ name: '',
+ status: 'done',
+ url: FormikName == ""? imageUrl : imageUrl?.replace("public", "/storage"),
+ thumbUrl: FormikName == ""? imageUrl : imageUrl?.replace("public", "/storage")
+ }
+ ];
+ const FilehandleChange = (value:any) => {
+
+ formik.setFieldValue(name, value.file.originFileObj)
+
+ };
+ const customRequest = async ({ onSuccess}: any) => {
+ onSuccess();
+ };
+ return (
+
+
+
+
+ }>
+ {placholder ?? t("upload_image") }
+
+
+ {isError ? "required" : ""}
+
+
+
+
+
+ )
+}
+
+export default File
\ No newline at end of file
diff --git a/src/Components/ValidationField/View/MaltyFile.tsx b/src/Components/ValidationField/View/MaltyFile.tsx
new file mode 100644
index 0000000..c383aea
--- /dev/null
+++ b/src/Components/ValidationField/View/MaltyFile.tsx
@@ -0,0 +1,52 @@
+import { Button, Upload } from 'antd';
+import { UploadOutlined } from '@ant-design/icons';
+import { ImageBaseURL } from '../../../api/config';
+import { useTranslation } from 'react-i18next';
+import useFormField from '../../../Hooks/useFormField';
+
+const MaltyFile = ({ name, label, onChange, isDisabled, placholder, className, props }: any) => {
+ const { formik, t, isError } = useFormField(name, props);
+ const imageUrl = formik?.values[name] ? ImageBaseURL + formik.values[name] : '';
+ const fileList = formik?.values[name] ? formik?.values[name]?.map((file: any, index: number) => ({
+ uid: index,
+ name: file.name,
+ status: 'done',
+ url: file.url || '',
+ thumbUrl: file.url || '',
+ })) : [];
+
+ const FilehandleChange = ({ file, fileList }: any) => {
+ formik.setFieldValue(name, fileList.map((file: any) => file.originFileObj));
+ };
+
+ const customRequest = async ({ onSuccess }: any) => {
+ // Perform any necessary actions before onSuccess is called
+ onSuccess();
+ };
+
+ return (
+
+
+
+
+ }>
+ {placholder ?? t("upload_image")}
+
+ {isError ? "required" : ""}
+
+
+ );
+};
+
+export default MaltyFile;
diff --git a/src/Components/ValidationField/View/SearchField.tsx b/src/Components/ValidationField/View/SearchField.tsx
new file mode 100644
index 0000000..47f7271
--- /dev/null
+++ b/src/Components/ValidationField/View/SearchField.tsx
@@ -0,0 +1,69 @@
+import { Form, Select } from 'antd';
+import React, { useEffect, useState } from 'react';
+import useFormField from '../../../Hooks/useFormField';
+import { useLocation, useNavigate } from 'react-router-dom';
+
+const SearchField = ({ name, label, placeholder, isDisabled, searchBy, option, isMulti, onChange, className, loading,props }: any) => {
+ const { errorMsg, isError, t, formik } = useFormField(name, props);
+ const [searchQuery, setSearchQuery] = useState('');
+ const location = useLocation()
+
+ const navigate = useNavigate()
+ useEffect(() => {
+ const searchParams = new URLSearchParams(location?.search);
+ setSearchQuery(searchParams?.get('search') || '');
+ console.log(searchParams);
+
+ }, [location]);
+
+
+
+ const SelecthandleChange = (value: { value: string; label: React.ReactNode }) => {
+ formik?.setFieldValue(name, value);
+
+ console.log(value);
+ };
+ const SearchHandleChange = (value:any) => {
+ if (value || value !== "") {
+ navigate(`${window?.location?.pathname}?${searchBy}=${value}`);
+ } else {
+ const params = new URLSearchParams(location.search);
+ params.delete(searchBy ?? "search");
+ navigate(`${window?.location.pathname}?${params.toString()}`);
+ }
+
+ };
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default React.memo(SearchField);
diff --git a/src/Components/ValidationField/View/SelectField.tsx b/src/Components/ValidationField/View/SelectField.tsx
new file mode 100644
index 0000000..b923d8b
--- /dev/null
+++ b/src/Components/ValidationField/View/SelectField.tsx
@@ -0,0 +1,41 @@
+import { Form, Select } from 'antd'
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+
+const SelectField = ({ name, label, placeholder, isDisabled,option,isMulti,onChange,className, props}: any) => {
+
+ const { errorMsg, isError, t ,formik} = useFormField(name, props)
+ const SelecthandleChange = (value: { value: string; label: React.ReactNode }) => {
+ formik.setFieldValue(name, value)
+
+ };
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default React.memo(SelectField);
diff --git a/src/Components/ValidationField/View/TextArea.tsx b/src/Components/ValidationField/View/TextArea.tsx
new file mode 100644
index 0000000..62b9794
--- /dev/null
+++ b/src/Components/ValidationField/View/TextArea.tsx
@@ -0,0 +1,45 @@
+import { Form, Input } from 'antd'
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+const { TextArea } = Input;
+
+const TextAreaField = ({ name, label, placeholder, isDisabled, onChange, props,type }: any) => {
+ const { Field, formik, isError, errorMsg, t } = useFormField(name, props);
+
+
+
+ const handleChange = (e: React.ChangeEvent) => {
+ console.log('Change:', e.target.value);
+ formik.setFieldValue(name, e.target.value)
+
+ };
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default React.memo(TextAreaField);
+;
diff --git a/src/Components/ValidationField/View/Time.tsx b/src/Components/ValidationField/View/Time.tsx
new file mode 100644
index 0000000..3d3bb0c
--- /dev/null
+++ b/src/Components/ValidationField/View/Time.tsx
@@ -0,0 +1,41 @@
+import { Form, TimePicker } from 'antd'
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+
+const Time = ({ name, label,className,isDisabled,onChange,props }: any) => {
+
+ const { errorMsg, isError, t, formik } = useFormField(name, props)
+ const onCalendarChange = (value: any) => {
+
+ formik.setFieldValue(name, value)
+
+ };
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Time
\ No newline at end of file
diff --git a/src/Components/ValidationField/View/index.tsx b/src/Components/ValidationField/View/index.tsx
new file mode 100644
index 0000000..606e8e6
--- /dev/null
+++ b/src/Components/ValidationField/View/index.tsx
@@ -0,0 +1,22 @@
+import Time from "./Time";
+import SelectField from "./SelectField";
+import Date from "./Date";
+import DataRange from "./DataRange";
+import CheckboxField from "./CheckboxField";
+import Default from "./Default";
+import File from "./File";
+import TextAreaField from './TextArea'
+
+
+
+export {
+ Time,
+ SelectField,
+ Date,
+ DataRange,
+ CheckboxField,
+ Default,
+ File,
+ TextAreaField
+
+}
\ No newline at end of file
diff --git a/src/Components/ValidationField/index.tsx b/src/Components/ValidationField/index.tsx
new file mode 100644
index 0000000..ee84bc7
--- /dev/null
+++ b/src/Components/ValidationField/index.tsx
@@ -0,0 +1,21 @@
+import { useState } from 'react';
+import { ErrorMessage, useField, Field, useFormikContext } from 'formik';
+import { useTranslation } from 'react-i18next';
+import { FaExclamationCircle } from 'react-icons/fa';
+import Select from 'react-select';
+import { convert_data_to_select } from '../../Layout/app/Const';
+
+
+
+
+
+export {
+ useState,
+ ErrorMessage, useField, Field, useFormikContext,
+ useTranslation,
+ FaExclamationCircle,
+ Select,
+ convert_data_to_select,
+
+
+}
\ No newline at end of file
diff --git a/src/Components/ValidationField/types.ts b/src/Components/ValidationField/types.ts
new file mode 100644
index 0000000..dd78185
--- /dev/null
+++ b/src/Components/ValidationField/types.ts
@@ -0,0 +1,133 @@
+
+// export interface ValidationFieldProps {
+// name: string;
+// type?: "text" | "Select" | "DataRange" | "Date" | "Time" | "File" | "number" | "Checkbox" | "password";
+// placeholder?: string;
+// label?: string;
+// className?: string;
+// option?: any[];
+// isMulti?: boolean;
+// isDisabled?: boolean;
+// picker?: "data" | "week" | "month" | "quarter" | "year";
+// Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM";
+// onChange?: (value: any) => void;
+// Group?: boolean
+// dir?:'ltr' | "rtl"
+// }
+
+ export interface ValidationFieldPropsText {
+ name: string;
+ type: "text";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+ }
+
+ export interface ValidationFieldPropsSelect {
+ name: string;
+ type: "Select";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?:any;
+ dir?:'ltr' | "rtl";
+ option: any[];
+ isMulti?: boolean;
+
+ }
+
+ export interface ValidationFieldPropsSearch{
+ name: string;
+ type: "Search";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl";
+ option: any[];
+ isMulti?: boolean;
+ searchBy:string;
+ loading?:boolean;
+
+ }
+ export interface ValidationFieldPropsDataRange {
+ name: string;
+ type: "DataRange";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+ Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM" | "YYYY-MM-DD HH:mm:ss.SSS";
+ }
+ export interface ValidationFieldPropsDate {
+ name: string;
+ type: "Date";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+ picker?: "data" | "week" | "month" | "quarter" | "year";
+ Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM" | "YYYY-MM-DD HH:mm:ss.SSS" | "YYYY-MM-DD HH:MM:SS";
+
+
+ }
+
+ export interface ValidationFieldPropsTime {
+ name: string;
+ type: "Time";
+ label?: string;
+ placeholder?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+
+ }
+
+ export interface ValidationFieldPropsFile {
+ name: string;
+ type: "File" | "MaltyFile";
+ acceptedFileType?:string;
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+
+ }
+ export interface ValidationFieldPropsCheckbox {
+ name: string;
+ type: "Checkbox";
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+ Group?: boolean
+
+ }
+ export interface ValidationFieldPropstext {
+ name: string;
+ type?: "text" | "number" | "password" | "TextArea";
+ label?: string;
+ className?: string;
+ placeholder?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+ Group?: boolean
+
+ }
+
+
+ export type ValidationFieldProps = ValidationFieldPropsText| ValidationFieldPropsSelect| ValidationFieldPropsDataRange| ValidationFieldPropsDate| ValidationFieldPropsTime| ValidationFieldPropsFile| ValidationFieldPropsCheckbox| ValidationFieldPropstext | ValidationFieldPropsSearch;
diff --git a/src/Components/order/OrderStatus.tsx b/src/Components/order/OrderStatus.tsx
new file mode 100644
index 0000000..79c46fb
--- /dev/null
+++ b/src/Components/order/OrderStatus.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+
+// for write later
+function OrderStatus() {
+ return (
+ OrderStatus
+ )
+}
+
+export default OrderStatus
\ No newline at end of file
diff --git a/src/Extensions/Editor/HtmlEditor.tsx b/src/Extensions/Editor/HtmlEditor.tsx
new file mode 100644
index 0000000..9d02c9b
--- /dev/null
+++ b/src/Extensions/Editor/HtmlEditor.tsx
@@ -0,0 +1,42 @@
+import React, { FC } from "react";
+import { Editor } from '@tinymce/tinymce-react';
+import { useFormikContext } from "formik";
+
+interface HtmlEditorProps {
+ langCode: number;
+ name: string;
+ editorState: string;
+}
+
+const HtmlEditor: FC = ({ langCode, name, editorState, ...props }) => {
+ const formik = useFormikContext();
+
+ const ar: boolean = langCode === 2;
+
+ return (
+ {
+ formik.setFieldValue(name, newValue)
+ }}
+ />
+ );
+}
+
+export { HtmlEditor };
\ No newline at end of file
diff --git a/src/Extensions/Editor/SingleLangEditor.tsx b/src/Extensions/Editor/SingleLangEditor.tsx
new file mode 100644
index 0000000..c8db2d6
--- /dev/null
+++ b/src/Extensions/Editor/SingleLangEditor.tsx
@@ -0,0 +1,43 @@
+import React, { FC } from "react";
+// import PropTypes from "";
+import { HtmlEditor } from "./HtmlEditor";
+import { useFormikContext } from "formik";
+import { useTranslation } from "react-i18next";
+
+interface SingleLangEditorProps {
+ langCode: number;
+ property: string;
+}
+
+const PROPERTY_TYPES: string[] = [
+ "privacy_description",
+ "conditions_description",
+ "about_us_description",
+ "product_description",
+ "auction_description"
+];
+
+const SingleLangEditor: FC = ({ langCode, property }) => {
+ const formik:any = useFormikContext();
+ const {t} = useTranslation();
+
+ const label = `${t(property)} (${t(`lang_${langCode}`)})`;
+ const fieldName = `translated_fields[${langCode}][${property}]`;
+ return (
+ <>
+ {label}
+
+ >
+ );
+};
+
+// SingleLangEditor.propTypes = {
+// langCode: PropTypes.oneOf([1, 2]).isRequired,
+// property: PropTypes.oneOf(PROPERTY_TYPES).isRequired,
+// };
+
+export default SingleLangEditor;
\ No newline at end of file
diff --git a/src/Extensions/Editor/StatusCard.tsx b/src/Extensions/Editor/StatusCard.tsx
new file mode 100644
index 0000000..25993c4
--- /dev/null
+++ b/src/Extensions/Editor/StatusCard.tsx
@@ -0,0 +1,23 @@
+import React, { FC } from "react";
+import { Card, CardBody, Spinner } from "reactstrap";
+
+interface StatusCardProps {
+ isLoading: boolean;
+ isError: boolean;
+}
+
+const StatusCard= ({ isLoading, isError }:StatusCardProps) => {
+ return (
+
+
+ {isLoading && }
+ {isError && Failed !
}
+
+
+ );
+};
+
+export default StatusCard;
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateAddModal.js b/src/Extensions/FileGenerator/generateAddModal.js
new file mode 100644
index 0000000..88f656f
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateAddModal.js
@@ -0,0 +1,65 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+let FileContiner = `
+
+import React from 'react'
+import LayoutModal from '../../Layout/Dashboard/LayoutModal'
+import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
+import { useAdd${capitalizeFirstLetter(fileName)} } from '../../api/${(fileName)}'
+import { getDataToSend, getInitialValues, getValidationSchema } from './formUtil'
+import { QueryStatusEnum } from '../../config/QueryStatus'
+import { useTranslation } from 'react-i18next'
+
+function Add${capitalizeFirstLetter(fileName)}Modal() {
+
+
+ const [t] = useTranslation()
+ const {mutate , status} = useAdd${capitalizeFirstLetter(fileName)}()
+ const handelSubmit = (values:any )=>{
+
+ const dataToSend = getDataToSend(values)
+
+ mutate(dataToSend)
+ // Submit Value
+ }
+ return (
+
+
+
+
+ )
+}
+
+export default Add${capitalizeFirstLetter(fileName)}Modal
+
+`
+fs.writeFileSync('src/Pages/'+fileName+"/"+"Add"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateApi.js b/src/Extensions/FileGenerator/generateApi.js
new file mode 100644
index 0000000..80d596e
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateApi.js
@@ -0,0 +1,40 @@
+const fs = require('fs');
+
+const fileName = process.argv[2]
+
+
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+
+let FileContiner = `
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetQuery from "./helper/useGetQuery"
+import useUpdateMutation from "./helper/useUpdateMutation"
+
+ const API = {
+ GET: "/api/admin/${fileName}",
+ ADD: "/api/admin/${fileName}/create",
+ UPDATE: "/api/admin/${fileName}/update",
+ DELETE: "/api/admin/${fileName}/delete",
+ };
+
+ const KEY = "${fileName.toUpperCase()}";
+ export const useGet${capitalizeFirstLetter(fileName)} = (params?:any) => useGetQuery(KEY, API.GET, params);
+ export const useAdd${capitalizeFirstLetter(fileName)} = () => useAddMutation(KEY, API.ADD);
+ export const useUpdate${capitalizeFirstLetter(fileName)} = () => useUpdateMutation(KEY, API.UPDATE);
+ export const useDelete${capitalizeFirstLetter(fileName)} = () =>useDeleteMutation(KEY, API.DELETE);
+`
+fs.writeFileSync('src/api/'+fileName+".ts",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateColumn.js b/src/Extensions/FileGenerator/generateColumn.js
new file mode 100644
index 0000000..c85ad21
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateColumn.js
@@ -0,0 +1,63 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+
+
+let FileContiner = `
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../Components/Ui/tables/Actions";
+
+function fnDelete(props :any ){}
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+
+ return useMemo(
+ () => [
+
+ {
+ name: t("email"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.email
+ },
+
+ {
+ name: "#",
+ sortable: false,
+ center: "true",
+ cell: (row) => (
+ row}
+ onView={()=>{}}
+ objectToEdit={row}
+ showEdit={true}
+ // showDelete={false}
+ onDelete={() => fnDelete({ id: row.id })}
+ />
+ ),
+ },
+ ],
+ [t]
+ );
+};
+
+export default useTableColumns;
+
+`
+fs.writeFileSync('src/Pages/'+fileName+"/useTableColumns"+".tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
diff --git a/src/Extensions/FileGenerator/generateDashboard.js b/src/Extensions/FileGenerator/generateDashboard.js
new file mode 100644
index 0000000..f291fd9
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateDashboard.js
@@ -0,0 +1,30 @@
+const { exec } = require('child_process');
+
+
+const fileName = process.argv[2]
+
+
+const CreateApi = `node src/Extensions/FileGenerator/generateApi.js ${fileName}`
+const CreatePage = `node src/Extensions/FileGenerator/generatePage.js ${fileName}`
+const CreateColumn = `node src/Extensions/FileGenerator/generateColumn.js ${fileName}`
+const CreateformUtil= `node src/Extensions/FileGenerator/generateformUtils.js ${fileName}`
+const CreateAddModal= `node src/Extensions/FileGenerator/generateAddModal.js ${fileName}`
+const CreateEditModal= `node src/Extensions/FileGenerator/generateEditModal.js ${fileName}`
+const CreateForm= `node src/Extensions/FileGenerator/generateForm.js ${fileName}`
+
+
+
+const RunCommand = async()=>{
+
+ exec(CreatePage)
+ exec(CreateApi)
+ setTimeout(()=>{},100)
+ exec(CreateColumn)
+ exec(CreateformUtil)
+ exec(CreateAddModal)
+ exec(CreateEditModal)
+ exec(CreateForm)
+
+}
+
+RunCommand()
diff --git a/src/Extensions/FileGenerator/generateEditModal.js b/src/Extensions/FileGenerator/generateEditModal.js
new file mode 100644
index 0000000..0171481
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateEditModal.js
@@ -0,0 +1,47 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+let FileContiner = `
+import React from 'react'
+import LayoutModal from '../../Layout/Dashboard/LayoutModal'
+import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
+import { getInitialValues, getValidationSchema } from './formUtil'
+import { usePageState } from '../../lib/state mangment/LayoutPagestate'
+
+function Edit${capitalizeFirstLetter(fileName)}Modal() {
+ const {objectToEdit} = usePageState()
+ return (
+ { }}
+ headerText='Edit Modal'
+ getValidationSchema={getValidationSchema(objectToEdit)}>
+
+
+ )
+}
+
+export default Edit${capitalizeFirstLetter(fileName)}Modal
+`
+fs.writeFileSync('src/Pages/'+fileName+"/"+"Edit"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateForm.js b/src/Extensions/FileGenerator/generateForm.js
new file mode 100644
index 0000000..3558bd6
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateForm.js
@@ -0,0 +1,66 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+let FileContiner = `
+import React from 'react'
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../Components/ValidationField/ValidationField';
+import { FakeSelectData } from '../../Layout/app/Const';
+import { useFormikContext } from 'formik';
+
+import { DatePicker } from 'antd';
+
+function Form${capitalizeFirstLetter(fileName)}() {
+ const formik = useFormikContext();
+
+
+
+ return (
+
+
+ // name from form utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form${capitalizeFirstLetter(fileName)}
+
+
+`
+fs.writeFileSync('src/Pages/'+fileName+'/Form'+ capitalizeFirstLetter(fileName)+".tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateModel.js b/src/Extensions/FileGenerator/generateModel.js
new file mode 100644
index 0000000..442421c
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateModel.js
@@ -0,0 +1,64 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+let FileContiner = `
+
+import React from 'react'
+import LayoutModal from '../../Layout/Dashboard/LayoutModal'
+import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
+import { useAdd${capitalizeFirstLetter(fileName)} } from '../../api/${(fileName)}'
+import { getDataToSend, getInitialValues, getValidationSchema } from './formUtil'
+import { QueryStatusEnum } from '../../config/QueryStatus'
+import { useTranslation } from 'react-i18next'
+
+function Add${capitalizeFirstLetter(fileName)}Modal() {
+
+
+ const [t] = useTranslation()
+ const {mutate , status} = useAdd${capitalizeFirstLetter(fileName)}()
+ const handelSubmit = (values:any )=>{
+
+ const dataToSend = getDataToSend(values)
+
+ mutate(dataToSend)
+ // Submit Value
+ }
+ return (
+
+
+
+
+ )
+}
+
+export default Add${capitalizeFirstLetter(fileName)}Modal
+
+`
+fs.writeFileSync('src/Pages/'+fileName+"/"+"Add"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generatePage.js b/src/Extensions/FileGenerator/generatePage.js
new file mode 100644
index 0000000..f200971
--- /dev/null
+++ b/src/Extensions/FileGenerator/generatePage.js
@@ -0,0 +1,67 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+const folderPath = 'src/Pages/'+fileName;
+
+
+if (!fs.existsSync(folderPath)) {
+ fs.mkdirSync(folderPath, { recursive: true });
+}
+
+let FileContiner = `
+import React from 'react'
+import DashBody from '../../Layout/Dashboard/DashBody'
+import DashHeader from '../../Layout/Dashboard/DashHeader'
+import LyTable from '../../Layout/Dashboard/LyTable'
+import useTableColumns from './useTableColumns'
+import { useGet${capitalizeFirstLetter(fileName)}} from '../../api/${fileName}'
+import { QueryStatusEnum } from '../../config/QueryStatus'
+import Edit${capitalizeFirstLetter(fileName)}Modal from './Edit${capitalizeFirstLetter(fileName)}Modal'
+import Add${capitalizeFirstLetter(fileName)}Modal from './Add${capitalizeFirstLetter(fileName)}Modal'
+
+function ${capitalizeFirstLetter(fileName)}Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGet${capitalizeFirstLetter(fileName)}()
+
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default ${capitalizeFirstLetter(fileName)}Page
+
+`
+
+fs.writeFileSync('src/Pages/'+fileName+"/"+capitalizeFirstLetter(fileName)+"Page.tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateformUtils.js b/src/Extensions/FileGenerator/generateformUtils.js
new file mode 100644
index 0000000..f608f43
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateformUtils.js
@@ -0,0 +1,73 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+let FileContiner = `
+import * as Yup from "yup";
+import { buildFormData } from "../../api/helper/buildFormData";
+
+interface formUtilCommon {
+ name:string,
+ email:string
+}
+
+interface ObjectToEdit extends formUtilCommon {
+
+ id?:number,
+
+}
+
+interface InitialValues extends ObjectToEdit {
+
+}
+interface ValidateSchema extends formUtilCommon{
+
+}
+
+export const getInitialValues = (objectToEdit: ObjectToEdit | null = null): InitialValues => {
+
+
+ return {
+ id:objectToEdit?.id?? 0 ,
+ name:objectToEdit?.name ?? "",
+ email:objectToEdit?.email?? ""
+ }
+
+
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // validate input
+ return Yup.object().shape({
+ name:Yup.string().required('required'),
+ email:Yup.string().required("required")
+ });
+};
+
+export const getDataToSend = (values: any): FormData => {
+ const data = { ...values };
+
+
+ const formData = new FormData();
+ buildFormData(formData, data);
+ return formData;
+};
+
+`
+fs.writeFileSync('src/Pages/'+fileName+"/"+"formUtil.ts",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Hooks/WithDrawer.tsx b/src/Hooks/WithDrawer.tsx
new file mode 100644
index 0000000..4373fe1
--- /dev/null
+++ b/src/Hooks/WithDrawer.tsx
@@ -0,0 +1,45 @@
+import React, { useState, ReactNode } from 'react';
+import type { DrawerProps } from 'antd';
+import { Drawer, Space } from 'antd';
+
+interface WithDrawerProps {
+ button: React.ReactNode;
+ children: ReactNode;
+ title:string;
+ className?:string,
+ iopen?:boolean,
+ setOpen:any
+}
+
+const WithDrawer: React.FC = ({ children,title ="Basic Drawer",className ,setOpen, iopen }) => {
+ const [placement, setPlacement] = useState('right');
+
+
+
+ return (
+ <>
+ setOpen(false)}
+ open={iopen}
+ key={placement}
+ >
+
+ {children}
+
+
+
+ >
+ );
+};
+
+export default WithDrawer;
+
+
+// Open}
+// >
+// {/* Your content goes here */}
+//
\ No newline at end of file
diff --git a/src/Hooks/imageUrlToFile.tsx b/src/Hooks/imageUrlToFile.tsx
new file mode 100644
index 0000000..255055b
--- /dev/null
+++ b/src/Hooks/imageUrlToFile.tsx
@@ -0,0 +1,13 @@
+export async function fetchImage(imageUrl:any) {
+ try {
+ const response = await fetch(imageUrl);
+ if (!response.ok) {
+ throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`);
+ }
+ const blob = await response.blob();
+ return new File([blob], 'image.png', { type: 'image/png' });
+ } catch (error) {
+ console.error('Error fetching image:', error);
+ return null;
+ }
+ }
diff --git a/src/Hooks/isEmpty.tsx b/src/Hooks/isEmpty.tsx
new file mode 100644
index 0000000..e20a5fe
--- /dev/null
+++ b/src/Hooks/isEmpty.tsx
@@ -0,0 +1,3 @@
+export const isEmpty = (Type:any) => {
+ return !Type || (Array.isArray(Type) && Type.length === 0);
+ };
\ No newline at end of file
diff --git a/src/Hooks/useChangeLanguage.tsx b/src/Hooks/useChangeLanguage.tsx
new file mode 100644
index 0000000..2e52a1f
--- /dev/null
+++ b/src/Hooks/useChangeLanguage.tsx
@@ -0,0 +1,75 @@
+import { useEffect } from 'react';
+import { initReactI18next, useTranslation } from 'react-i18next';
+import i18n from 'i18next';
+import translationEN from '../translate/en.json';
+import translationAR from '../translate/ar.json';
+import translationDE from '../translate/de.json';
+
+const language = localStorage.getItem('language') ?? 'en';
+
+i18n.use(initReactI18next).init({
+ resources: {
+ en: {
+ translation: translationEN
+ },
+ ar: {
+ translation: translationAR
+ },
+ de: {
+ translation: translationDE
+ }
+ },
+ lng: language,
+ interpolation: {
+ escapeValue: false
+ }
+ });
+
+
+export function useLanguage() {
+ useEffect(() => {
+ changeLanguage(language);
+ }, [language]);
+
+ const changeLanguage = (newLanguage:any) => {
+ i18n.changeLanguage(newLanguage);
+ localStorage.setItem('language', newLanguage);
+ applyLanguageStyles(newLanguage);
+ };
+
+ return { changeLanguage };
+}
+
+function applyLanguageStyles(language:any) {
+ if (language === 'ar') {
+ document.body.setAttribute('dir', 'rtl');
+ document.body.classList.remove('de');
+ document.body.classList.add('ar');
+ } else if (language === 'en') {
+ document.body.setAttribute('dir', 'ltr');
+ document.body.classList.remove('ar', 'de');
+ document.body.classList.add('en');
+ } else if (language === 'de') {
+ document.body.setAttribute('dir', 'ltr');
+ document.body.classList.remove('ar');
+ document.body.classList.add('de');
+ }
+
+}
+
+export function useLanguageMenu() {
+ const { t } = useTranslation();
+ const { changeLanguage } = useLanguage();
+
+ const languageOptions = [
+ { code: 'ar', icon: '/language/ar.svg', label: t('Arabic') },
+ { code: 'en', icon: '/language/en.svg', label: t('English') },
+ { code: 'de', icon: '/language/de.svg', label: t('German') }
+ ];
+
+ const handleLanguageChange = (code:any) => {
+ changeLanguage(code);
+ };
+
+ return { languageOptions, handleLanguageChange };
+}
diff --git a/src/Hooks/useEventListener.tsx b/src/Hooks/useEventListener.tsx
new file mode 100644
index 0000000..0c29a4a
--- /dev/null
+++ b/src/Hooks/useEventListener.tsx
@@ -0,0 +1,16 @@
+import { useEffect, useRef } from "react";
+
+export const useEventListener = (eventType:any, callback:any, element = window) => {
+ const callbackRef = useRef(callback);
+
+ useEffect(() => {
+ callbackRef.current = callback;
+ }, [callback]);
+
+ useEffect(() => {
+ const handler = (e:any) => callbackRef.current(e);
+ element.addEventListener(eventType, handler);
+
+ return () => element.removeEventListener(eventType, handler);
+ }, [eventType, element]);
+};
diff --git a/src/Hooks/useFormField.tsx b/src/Hooks/useFormField.tsx
new file mode 100644
index 0000000..57d8cbf
--- /dev/null
+++ b/src/Hooks/useFormField.tsx
@@ -0,0 +1,16 @@
+import { useField, useFormikContext } from 'formik';
+import { useTranslation } from 'react-i18next';
+import { Field } from 'formik';
+
+const useFormField = (name: string, props?: any) => {
+ const [field, meta] = useField({ name, ...props });
+ const { t } = useTranslation();
+ const formik = useFormikContext();
+ const isError = meta.touched && meta.error;
+
+ const errorMsg = meta.error ? t(meta.error.toString()) : '';
+
+ return { Field, field, meta, formik, isError, errorMsg, t };
+};
+
+export default useFormField;
diff --git a/src/Hooks/useFormatToSelect.tsx b/src/Hooks/useFormatToSelect.tsx
new file mode 100644
index 0000000..df460b3
--- /dev/null
+++ b/src/Hooks/useFormatToSelect.tsx
@@ -0,0 +1,15 @@
+const useFormatToSelect = (Data : any) => {
+ const format = (data :any) => {
+ if (!data) return [];
+
+ return data.map((item :any) => ({
+ value: item?.id,
+ label: item?.name,
+ }));
+ };
+
+ return format(Data);
+ };
+
+ export default useFormatToSelect;
+
\ No newline at end of file
diff --git a/src/Hooks/useImageError.tsx b/src/Hooks/useImageError.tsx
new file mode 100644
index 0000000..db0d853
--- /dev/null
+++ b/src/Hooks/useImageError.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+const useImageError = ({currentTarget}:any) => {
+ const ErrorImage = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/65/No-Image-Placeholder.svg/832px-No-Image-Placeholder.svg.png"
+ currentTarget.onerror = null;
+ currentTarget.src=`${ErrorImage}`;
+}
+
+export default useImageError
\ No newline at end of file
diff --git a/src/Hooks/useLoadingState.tsx b/src/Hooks/useLoadingState.tsx
new file mode 100644
index 0000000..dfda80d
--- /dev/null
+++ b/src/Hooks/useLoadingState.tsx
@@ -0,0 +1,21 @@
+import { useState, useEffect } from 'react';
+
+function useLoadingState(initialValue: boolean, duration: number): [boolean, () => void] {
+ const [loading, setLoading] = useState(initialValue);
+
+ useEffect(() => {
+ const timeoutId = setTimeout(() => {
+ setLoading(false);
+ }, duration);
+
+ return () => clearTimeout(timeoutId);
+ }, [duration]);
+
+ const resetLoading = () => {
+ setLoading(true);
+ };
+
+ return [loading, resetLoading];
+}
+
+export default useLoadingState;
diff --git a/src/Hooks/useNavigateOnSuccess.ts b/src/Hooks/useNavigateOnSuccess.ts
new file mode 100644
index 0000000..2b012c3
--- /dev/null
+++ b/src/Hooks/useNavigateOnSuccess.ts
@@ -0,0 +1,20 @@
+import React, { useEffect } from 'react'
+import { useNavigate } from 'react-router-dom'
+
+
+function useNavigateOnSuccess(isSuccess :boolean , to_path:string , callbackAfterSuccess?:any) {
+
+ const navigate = useNavigate()
+ useEffect(()=>{
+
+ if(isSuccess){
+ if (typeof callbackAfterSuccess === 'function') {
+ callbackAfterSuccess()
+ }
+ navigate(to_path )
+ }
+ },[isSuccess])
+
+}
+
+export default useNavigateOnSuccess
\ No newline at end of file
diff --git a/src/Hooks/usePagination.tsx b/src/Hooks/usePagination.tsx
new file mode 100644
index 0000000..5008afe
--- /dev/null
+++ b/src/Hooks/usePagination.tsx
@@ -0,0 +1,38 @@
+import { Pagination } from "antd";
+import { useTranslation } from "react-i18next";
+import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
+
+export const PaginationBody = ({ data }: any) => {
+ const navigate = useNavigate();
+ const location = useLocation();
+ const pagination = location?.search || '';
+ const currentPage = parseInt(new URLSearchParams(location.search).get("page") || "1", 10);
+ const pageSize = parseInt(new URLSearchParams(location.search).get("per_page") || "15", 10);
+
+ const [searchParams] = useSearchParams()
+ const onChange = (page: number, pageSize?: number) => {
+ navigate(`?page=${page}&per_page=${pageSize || data?.per_page}`);
+ };
+
+ const onShowSizeChange = (current: number, pageSize: number) => {
+ navigate(`?page=${current}&per_page=${pageSize}`);
+ };
+ const [t] = useTranslation()
+
+ return (
+ `${t(`Total`)} ${total} ${t(`items`)}`}
+ pageSize={pageSize}
+ pageSizeOptions={[6, 15, 22, 30]}
+ defaultCurrent={currentPage}
+ current={currentPage}
+ onChange={onChange}
+ onShowSizeChange={onShowSizeChange}
+ // showQuickJumper
+ showSizeChanger
+
+ />
+ );
+};
diff --git a/src/Hooks/useWindowSize.tsx b/src/Hooks/useWindowSize.tsx
new file mode 100644
index 0000000..853fdb8
--- /dev/null
+++ b/src/Hooks/useWindowSize.tsx
@@ -0,0 +1,18 @@
+import { useState } from "react";
+import { useEventListener } from "./useEventListener";
+
+export const useWindowSize = () => {
+ const [windowSize, setWindowSize] = useState({
+ width: window.innerWidth,
+ height: window.innerHeight,
+ });
+
+ useEventListener("resize", () => {
+ setWindowSize({
+ width: window.innerWidth,
+ height: window.innerHeight,
+ });
+ });
+
+ return windowSize;
+};
diff --git a/src/Layout/Dashboard/AddButton/AddButton.tsx b/src/Layout/Dashboard/AddButton/AddButton.tsx
new file mode 100644
index 0000000..d6d8cec
--- /dev/null
+++ b/src/Layout/Dashboard/AddButton/AddButton.tsx
@@ -0,0 +1,33 @@
+import React from 'react'
+import './Add_Button.scss'
+import { useTranslation } from 'react-i18next'
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate'
+
+
+
+const AddButton = (props :any) => {
+ const [t] = useTranslation();
+
+
+ return (
+
+
+
+
+ )
+}
+
+export default AddButton
\ No newline at end of file
diff --git a/src/Layout/Dashboard/AddButton/AddButtonLayout.tsx b/src/Layout/Dashboard/AddButton/AddButtonLayout.tsx
new file mode 100644
index 0000000..d796bae
--- /dev/null
+++ b/src/Layout/Dashboard/AddButton/AddButtonLayout.tsx
@@ -0,0 +1,41 @@
+import React from 'react'
+import './Add_Button.scss'
+import { useTranslation } from 'react-i18next'
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate'
+
+
+
+const AddButtonLayout = ({haveAddModal}:any) => {
+ const { setIsOpenAddModel , setObjectToEdit } = usePageState()
+ const [t] = useTranslation();
+
+
+ return (
+ {
+ if(haveAddModal){
+
+ setIsOpenAddModel()
+ }
+ setObjectToEdit(null)
+
+ }}>
+
+
+
+ )
+}
+
+export default AddButtonLayout
\ No newline at end of file
diff --git a/src/Layout/Dashboard/AddButton/Add_Button.scss b/src/Layout/Dashboard/AddButton/Add_Button.scss
new file mode 100644
index 0000000..fc7a862
--- /dev/null
+++ b/src/Layout/Dashboard/AddButton/Add_Button.scss
@@ -0,0 +1,77 @@
+.Add_Button{
+ button {
+ border: 2px solid var(--primary);
+ background-color: var(--primary);
+ border-radius: 0.5vw;
+ height: 40px;
+ width: 70px;
+ font-size: 1vw ;
+ display: flex; justify-content: center; align-items: center;
+ box-shadow: 2px 2px 7px 0 var(--primary);
+ }
+ button span {
+ display: flex;
+ align-items: center;
+ color: var(--bg);
+ font-weight: normal;
+ font-size: 14px;
+ }
+
+ button:hover {
+ background-color:var(--primary);
+ }
+}
+
+@media screen and (max-width: 700px) {
+ .Add_Button{
+ button{
+ font-size: 2vw !important;
+ }
+ }
+}
+@media screen and (max-width: 470px) {
+ .Add_Button{
+ button{
+ font-size: 3vw !important;
+ }
+ }
+}
+
+ .Add_Button_notification{
+ button {
+ border: 2px solid var(--primary);
+ background-color: var(--primary);
+ border-radius: 0.5vw;
+ height: 40px;
+ width: 180px;
+ font-size: 1vw ;
+ display: flex; justify-content: center; align-items: center;
+ box-shadow: 2px 2px 7px 0 var(--primary);
+ }
+ button span {
+ display: flex;
+ align-items: center;
+ color: var(--bg);
+ font-weight: normal;
+ font-size: 14px;
+ }
+
+ button:hover {
+ background-color:var(--primary);
+ }
+ }
+
+ @media screen and (max-width: 700px) {
+ .Add_Button_notification{
+ button{
+ font-size: 2vw !important;
+ }
+ }
+ }
+ @media screen and (max-width: 470px) {
+ .Add_Button_notification{
+ button{
+ font-size: 3vw !important;
+ }
+ }
+ }
diff --git a/src/Layout/Dashboard/DashBody.tsx b/src/Layout/Dashboard/DashBody.tsx
new file mode 100644
index 0000000..8f2f449
--- /dev/null
+++ b/src/Layout/Dashboard/DashBody.tsx
@@ -0,0 +1,32 @@
+import { Spinner } from "reactstrap"
+import { QueryStatusEnum } from "../../config/QueryStatus"
+import LoadingPage from "../app/LoadingPage"
+import { useTranslation } from "react-i18next"
+import { BsEmojiFrown } from "react-icons/bs";
+import ErrorPage from "../app/ErrorPage";
+
+
+const DashBody = ({ children , status }: { children: React.ReactNode ,status?:QueryStatusEnum }) => {
+ const {t} = useTranslation();
+
+ // Add You Custom Loadaing Page
+ if(status === QueryStatusEnum.LOADING){
+
+ return
+ }
+
+ // Add Your Custom Error Page
+ if(status === QueryStatusEnum.ERROR){
+ return (
+
+ )
+ }
+
+ return (
+
+ { children }
+
+ )
+}
+
+export default DashBody
diff --git a/src/Layout/Dashboard/DashHeader.tsx b/src/Layout/Dashboard/DashHeader.tsx
new file mode 100644
index 0000000..a71852d
--- /dev/null
+++ b/src/Layout/Dashboard/DashHeader.tsx
@@ -0,0 +1,27 @@
+import React from "react";
+import AddButtonLayout from "./AddButton/AddButtonLayout";
+import { useTranslation } from "react-i18next";
+
+interface DashHeaderProp {
+ title: string;
+ children?: React.ReactNode;
+ showAddButton?: boolean;
+ haveAddModal?:boolean
+}
+const DashHeader = ({
+ children,
+ title,
+ haveAddModal= true ,
+ showAddButton = true,
+}: DashHeaderProp) => {
+ const [t] = useTranslation();
+ return (
+
+
{t(`${title}`)}
+ {children}
+ {showAddButton &&
}
+
+ );
+};
+
+export default DashHeader;
diff --git a/src/Layout/Dashboard/FormPage.tsx b/src/Layout/Dashboard/FormPage.tsx
new file mode 100644
index 0000000..befc606
--- /dev/null
+++ b/src/Layout/Dashboard/FormPage.tsx
@@ -0,0 +1,42 @@
+import { Formik, Form } from 'formik';
+import React, { ReactNode } from 'react';
+import { Button } from "reactstrap";
+import * as Yup from 'yup';
+
+interface FormValues {
+ [key: string]: any;
+}
+
+interface FormPageProps {
+ handleSubmit: (values: any) => void
+ initialValues: FormValues;
+ validationSchema: any;
+ title?: string;
+ children: ReactNode;
+}
+
+const FormPage: React.FC = ({ children, handleSubmit, initialValues, validationSchema, title = "Edit Item" }) => {
+ return (
+ <>
+ {title}
+
+
+ {formik => (
+
+ )}
+
+
+ >
+ );
+};
+
+export default FormPage;
diff --git a/src/Layout/Dashboard/FormikForm.tsx b/src/Layout/Dashboard/FormikForm.tsx
new file mode 100644
index 0000000..9e42628
--- /dev/null
+++ b/src/Layout/Dashboard/FormikForm.tsx
@@ -0,0 +1,67 @@
+import { Formik, Form } from 'formik';
+import React, { ReactNode } from 'react';
+import { useTranslation } from 'react-i18next';
+import { Button } from "reactstrap";
+import * as Yup from 'yup';
+
+interface FormValues {
+ [key: string]: any;
+}
+
+interface FormikFormProps {
+ handleSubmit: (values: any) => void
+ initialValues: FormValues;
+ validationSchema: any;
+ title?: string;
+ children: ReactNode;
+ ButtonName?:string
+}
+const FormikForm: React.FC = ({ children, handleSubmit, initialValues, validationSchema, title = "Add New Item" ,ButtonName="إضافة"}) => {
+ const [t]= useTranslation()
+
+ return (
+ <>
+
+ {formik => (
+
+ )}
+
+ >
+ );
+};
+
+export default FormikForm;
+
+
+
+{/* {
+
+}}
+initialValues={() => {
+ return {
+ id: null,
+ name: "",
+
+ }
+}}
+validationSchema={() => {
+ return Yup.object().shape({
+ name: Yup.string().required('required'),
+
+ });
+}}
+
+>
+
+ */}
\ No newline at end of file
diff --git a/src/Layout/Dashboard/LayoutModal.tsx b/src/Layout/Dashboard/LayoutModal.tsx
new file mode 100644
index 0000000..926e7f0
--- /dev/null
+++ b/src/Layout/Dashboard/LayoutModal.tsx
@@ -0,0 +1,77 @@
+import { Form, Formik } from 'formik'
+import React, { useEffect } from 'react'
+import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'
+import { usePageState } from '../../lib/state mangment/LayoutPagestate'
+import { useTranslation } from 'react-i18next';
+import { LoadingButton } from '../../Components/Ui/LoadingButton';
+import { QueryStatusEnum } from '../../config/QueryStatus';
+
+interface LayoutModalProps {
+ isAddModal: boolean;
+ headerText: string;
+ handleSubmit: (values: any) => void;
+ getInitialValues: any;
+ getValidationSchema: any;
+ children: React.ReactNode;
+ status?:QueryStatusEnum
+}
+function LayoutModal({isAddModal , headerText , handleSubmit =()=>{} , getInitialValues , getValidationSchema,status ,children}:LayoutModalProps) {
+
+
+
+ const {isOpenAddModel ,setIsOpenAddModel , setIsOpenEditModel ,isOpenEditModel , objectToEdit , CloseAllModal} = usePageState(state => state)
+
+
+ useEffect(()=>{
+ if(status === QueryStatusEnum.SUCCESS){
+ CloseAllModal()
+ }
+ },[status , CloseAllModal])
+
+ const [t] = useTranslation()
+ return (
+
+ isAddModal ?setIsOpenAddModel() : setIsOpenEditModel()} >
+ {t(headerText)}
+
+ {
+
+ (( objectToEdit != null && isOpenEditModel) || isOpenAddModel) &&
+
+
+ {(formik) => (
+
+ )}
+
+ }
+
+
+ )
+}
+
+export default LayoutModal
\ No newline at end of file
diff --git a/src/Layout/Dashboard/LyTable.tsx b/src/Layout/Dashboard/LyTable.tsx
new file mode 100644
index 0000000..be96f09
--- /dev/null
+++ b/src/Layout/Dashboard/LyTable.tsx
@@ -0,0 +1,39 @@
+
+import DataTable from 'react-data-table-component';
+import { Card, CardBody, Spinner } from 'reactstrap';
+import { PaginationBody } from '../../Hooks/usePagination';
+import { useTranslation } from 'react-i18next';
+
+const LyTable = (props?: any) => {
+ const {t} = useTranslation();
+
+ return (
+
+
+
+ {t("no_records")}}
+ noHeader
+ pagination
+ progressComponent={}
+
+ {...(props.is_pagination && {
+ paginationServer: true,
+ paginationComponent: () =>
+ })}
+
+ {...props}
+ />
+
+
+
+
+
+ )
+}
+
+
+export default LyTable
\ No newline at end of file
diff --git a/src/Layout/Dashboard/PageStructure.tsx b/src/Layout/Dashboard/PageStructure.tsx
new file mode 100644
index 0000000..570254d
--- /dev/null
+++ b/src/Layout/Dashboard/PageStructure.tsx
@@ -0,0 +1,36 @@
+import React, { FC } from "react";
+import StatusCard from "../../Extensions/Editor/StatusCard";
+import { Card, CardHeader, CardBody, CardTitle } from "reactstrap";
+import { useTranslation } from "react-i18next";
+
+interface PageStructureProps {
+ title?: string;
+ isLoading: boolean;
+ isError: boolean;
+ data?: any;
+ children:any
+}
+
+const PageStructure: FC = ({
+ title,
+ isLoading,
+ isError,
+ data,
+ children,
+}) => {
+ const {t} = useTranslation();
+
+ if (!data) return ;
+ return (
+
+ {title && (
+
+ {t(title)}
+
+ )}
+ {children}
+
+ );
+};
+
+export default PageStructure;
\ No newline at end of file
diff --git a/src/Layout/Dashboard/SearchField.tsx b/src/Layout/Dashboard/SearchField.tsx
new file mode 100644
index 0000000..02b03d2
--- /dev/null
+++ b/src/Layout/Dashboard/SearchField.tsx
@@ -0,0 +1,56 @@
+import { Input } from 'antd';
+import { SearchProps } from 'antd/es/input'
+import { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';
+const { Search } = Input;
+
+const SearchField = ({ searchBy }: any) => {
+ const navigate = useNavigate()
+ const [searchParams,] = useSearchParams();
+ const location = useLocation()
+ const { t } = useTranslation();
+
+
+ const [searchValue, setSearchValue] = useState(searchParams.get(searchBy ?? "search") || "");
+
+ const onSearch: SearchProps['onSearch'] = (value, _e, info) => {
+ if (value || value !== "") {
+ navigate(`${location?.pathname}?${searchBy ?? "search"}=${value}`);
+ } else {
+ const params = new URLSearchParams(location.search);
+ params.delete(searchBy ?? "search");
+ navigate(`${location.pathname}?${params.toString()}`);
+ }
+ }
+
+ const onChange = (e: any) => {
+ const value = e.target.value
+ setSearchValue(e.target.value);
+ if (value === "") {
+ const params = new URLSearchParams(location.search);
+ params.delete(searchBy ?? "search");
+ navigate(`${location.pathname}?${params.toString()}`);
+ }
+ }
+
+
+ return (
+
+
+
+
+ )
+}
+
+export default SearchField
\ No newline at end of file
diff --git a/src/Layout/Dashboard/SelectField.tsx b/src/Layout/Dashboard/SelectField.tsx
new file mode 100644
index 0000000..a770134
--- /dev/null
+++ b/src/Layout/Dashboard/SelectField.tsx
@@ -0,0 +1,39 @@
+import { Select } from 'antd';
+import React, { useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useLocation, useNavigate } from 'react-router-dom';
+
+const SelectField = ({ selectBy, lebel, option }: any) => {
+ const [searchQuery, setSearchQuery] = useState('');
+ const location = useLocation();
+ const navigate = useNavigate();
+ const [t] = useTranslation();
+
+ useEffect(() => {
+ const searchParams = new URLSearchParams(location.search);
+ setSearchQuery(searchParams.get('search') || '');
+ }, []);
+
+
+ const handleSelectChange = (value: any) => {
+ if (value) {
+ console.log(`${location.pathname}?${selectBy}=${value}`);
+ navigate(`${location.pathname}?${selectBy}=${value}`);
+ }
+ }
+
+ return (
+
+
+
+ );
+};
+
+export default React.memo(SelectField);
diff --git a/src/Layout/Dashboard/SelectWSearchField.tsx b/src/Layout/Dashboard/SelectWSearchField.tsx
new file mode 100644
index 0000000..bd28411
--- /dev/null
+++ b/src/Layout/Dashboard/SelectWSearchField.tsx
@@ -0,0 +1,52 @@
+import { Select } from 'antd';
+import React, { useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useLocation, useNavigate } from 'react-router-dom';
+
+const SelectWSearchField = ({ selectBy, submiteBy, lebel, option }: any) => {
+ const [searchQuery, setSearchQuery] = useState('');
+ const location = useLocation();
+ const navigate = useNavigate();
+ const [t] = useTranslation();
+
+ useEffect(() => {
+ const searchParams = new URLSearchParams(location.search);
+ setSearchQuery(searchParams.get('search') || '');
+ }, []);
+
+ const handleSearchChange = (value: any) => {
+ if (value || value !== "") {
+ navigate(`${location.pathname}?${selectBy}=${value}`);
+ } else {
+ const params = new URLSearchParams(location.search);
+ params.delete(selectBy ?? "search");
+ navigate(`${location.pathname}?${params.toString()}`);
+ }
+ };
+
+ const handleSelectChange = (value: any) => {
+ if (value) {
+ console.log(`${location.pathname}?${submiteBy}=${value}`);
+
+ navigate(`${location.pathname}?${submiteBy}=${value}`);
+ }
+}
+
+ return (
+
+
+
+ );
+};
+
+export default React.memo(SelectWSearchField);
diff --git a/src/Layout/Dashboard/ViewPage.tsx b/src/Layout/Dashboard/ViewPage.tsx
new file mode 100644
index 0000000..74322e0
--- /dev/null
+++ b/src/Layout/Dashboard/ViewPage.tsx
@@ -0,0 +1,80 @@
+import React from "react";
+import { Card, CardHeader, CardTitle, CardBody, Button } from "reactstrap";
+import { Formik, Form } from "formik";
+import { LoadingButton } from "../../Components/Ui/LoadingButton";
+import ProgressBar from "../../Components/Ui/ProgressBar";
+import { useLocation, useNavigate } from "react-router-dom";
+import { usePageState } from "../../lib/state mangment/LayoutPagestate";
+import { useTranslation } from "react-i18next";
+
+type TViewPage ={
+ children: React.ReactNode,
+ getInitialValues:any,
+ getValidationSchema:any,
+ handleSubmit:any,
+ // BarStatus:any,
+ IsloadingButton:boolean
+}
+
+const ViewPage: React.FC= ({children,getInitialValues, getValidationSchema,handleSubmit,IsloadingButton})=> {
+
+ const {objectToEdit} = usePageState()
+ const {t} = useTranslation();
+ const navigate = useNavigate();
+ // console.log(BarStatus);
+
+ const location = useLocation();
+
+
+
+ const navigateToParent = () => {
+ navigate(-1)
+ };
+
+ return (
+
+
+
+ {t("View_information")}
+
+
+
+
+ {
+
+ {(formik) => (
+
+ )}
+
+ }
+
+
+
+ );
+};
+
+
+export default ViewPage;
diff --git a/src/Layout/Dashboard/useCloseModal.ts b/src/Layout/Dashboard/useCloseModal.ts
new file mode 100644
index 0000000..993685d
--- /dev/null
+++ b/src/Layout/Dashboard/useCloseModal.ts
@@ -0,0 +1,18 @@
+import React, { useEffect } from 'react'
+import { usePageState } from '../../lib/state mangment/LayoutPagestate'
+
+function useCloseModal(statusClose:any) {
+
+ const {CloseAllModal} = usePageState()
+
+ useEffect(()=>{
+
+ if(statusClose){
+ CloseAllModal()
+ }
+ },[statusClose , CloseAllModal])
+
+ return true
+}
+
+export default useCloseModal
\ No newline at end of file
diff --git a/src/Layout/app/Const.tsx b/src/Layout/app/Const.tsx
new file mode 100644
index 0000000..bb3c0cb
--- /dev/null
+++ b/src/Layout/app/Const.tsx
@@ -0,0 +1,48 @@
+export const SideBarLogoUrl = "../Layout/KarimLogo.svg";
+export const UserImageURL = "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMsaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjUtYzAxNCA3OS4xNTE0ODEsIDIwMTMvMDMvMTMtMTI6MDk6MTUgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4RDI0Q0Q2RjcxQ0ExMUU1QjA2Q0JBMTlGNjJDRUVCMyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4RDI0Q0Q3MDcxQ0ExMUU1QjA2Q0JBMTlGNjJDRUVCMyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjhEMjRDRDZENzFDQTExRTVCMDZDQkExOUY2MkNFRUIzIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjhEMjRDRDZFNzFDQTExRTVCMDZDQkExOUY2MkNFRUIzIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgB9AH0AwERAAIRAQMRAf/EAHwAAQACAwEBAAAAAAAAAAAAAAABBgMEBQcCAQEAAAAAAAAAAAAAAAAAAAAAEAEAAgECAwQIBAIHCQEAAAAAAQIDEQQhBQYxQVESYXGBkSIyQhOxwVIjoRTRYjNTJBU14XKCkrLiQ4NUFhEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A9cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAJAAAABAJAAAAAABAJAAAAAAAAAAAAABAJAABAJAAAAAAAAAAAAAAAAAAAAAAAAAAABAJAAAAAAAAAAAAAABAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAJAAAAAAAAAAAAAABAJA1AAAAAAAAAAAAAAAAAAAAAAABAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB948OXJPlx0m8z3RGoN/B07zbNETGCaRP65iv4g3cXR29tGuTNjp6I1mfwBsV6M/XutPDSmv5wCf/xeP/65/wCT/uBjt0Zk4+Tc1nw1rMA1s3SXM6fJNMnqnT8dAaG45RzLb/2mC0R+qI1j3wDTmJidJjQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAmImZ0iNZ8IB1Nl05zHc+W00+1jn6r8OHqBYNn0ry/DpbLrntw+bhHD0QDq4dvgw18uLHWkf1YiAZAAAAAAAau55XsNzExlw1mZ+qI0n3wDib7pCsxNtnk0ntjHfs9WoOBu+W73aTpnxTWPHtj3g1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbvLuUbzfX/arpjifiyT2QC2ct6f2WymL6fdzfrt+UA6gAAAAAAAAAAAPnJix5aTTJWLVnhMTxBXOZ9J0ms5NjOlv7qez2SCtZsGXBknHlrNL14TEg+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd7kvTd9zEZ91rXD21p32BbMWLHixxjx1ilKxpEQD7AAAAAAAAAAAAAABpcy5Ttd/j8uWumSPlyR2wCl8y5Zudhm+3ljWs/JeOyYBpgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3T/T1ZrTebyuuvxYsM+HdNtf4As4AAAAAAAAAAAAAAAAAMO72mDd4LYc9fNS3vifGAUfnHKMvLtx5Z1thvxxZPGPCfTANAAAAAAAAAAAAAAAAAAAAAAAAAAEAkAAAAAAAAAAAAAFg6b5H9+0bzcV/arOuKs/VMd/qBbQAAAAAAAAAAAAAAAAAAAYN7s8O8218GWNa27J74numAUPmXL82x3VsOSOHbS3daviDVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0OS8stv93FJ4YqfFln0eAL3jx0x4648cRWlY0rEeAPoAAAAAAAAAAAAAAAAAAAAHO51yqm/2sxpEZ6ccd/yBRL0tS81tGlqzpMemAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACa1ta0VrGtrTpER3yC+cj5fGy2NKTH7t/iyT6Z7gdAAAAAAAAAAAAAAAAAAAAAAAFT6r5ZOPNG8x1+C/DJp3T4+0FeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2ultjGffTmvGtMMax4ebuBcwAAAAAAAAAAAAAAAAAAAAAAAYd5tqbnbZMN41reJj2g87zYrYst8duFqTMTHqB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvXT2zjbctx6xHnyfHaY9PYDpgAAAAAAAAAAAAAAAAAAAAAAAAp/VuzjFva56xEVzRx0/VAOEAAAAAAAAAAAAAAAAAAAAAACASACASAAAAAAADY5ft53G9w4YjXz2iJ9QPRK1itYrHZEaR7ASAAAAAAAAAAAAAAAAAAAAAAAADk9T7X73K72iNbYpi8ervBSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdvpLBGTmU5J/wDFSZ9s8AXIAAAAAAAAAAAAAAAAAAAAAAAAAGPcYozYMmKey9Zr74B5vkr5L2r+mZj3AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFp6NxR9vcZe/WtY/EFkAAAAAAAAAAAAAAAAAAAAAAAAAAB57zfFGLmW4pHZF50BqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuPSFJjl17d1sk6eyIB3AAAAAAAAAAAAAAAAAAAAAAAAAAAUbqWs15xm17/LPvgHLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABc+kv9K/8AZb8IB2gAAAAAAAAAAAAAAAAAAAAAAAAAAUjqn/Wcv+7T/pgHJAAAAAAAAAAAAAAAAAAAAAAAAAAABAJAAAABcOkLzPL8ldflyTw9cA7oAAAAAAAAAAAAAAAAAAAAAAAAAAKL1Jebc4z8ddNI90A5gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALP0Zl+HcYfVaPwBZgAAAAAAAAAAAAAAAAAAAAAAAAAAeec1y/e5juMnda86A1QAQCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdnpTcfa5n5J7MtZr7uILoAAAAAAAAAAAAAAAAAAAAAAAAADFus0Ydtlyz9FZn3QDzi9vNe1vGZn3ggEAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGbZZ5wbrFmidJpaJ1B6LjvW9K3rOsWiJifWD6AAAAAAAAAAAAAAAAAAAAAAAABxuqd19rls44nS2aYrp6I4yClgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu/TW9jccurWba5MPw2j0dwOsAAAAAAAAAAAAAAAAAAAAAAAACmdVb2M+/wDs1trTDGn/ABT2g4oAAAAAAAAAAAAAAAAAAAAAAAIABIAAIBIAAAAAOv0zvo23MIpedKZo8s+GvcC7AAAAAAAAAAAAAAAAAAAAAAAA1+Ybum02mTPfsrHD0z3A88yZLZMlr2+a0zM+0HyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEzE6xwmOyQXnp/mUbzY1i1tc+L4ckd/okHUAAAAAAAAAAAAAAAAAAAAAABTuqeZ/f3MbbFbXFi+bSeE2/2A4YAAAAAAAAAAAAAAAAAAAAAAAAIBIAAAAAAAAAAANzlXMcmw3dc1eNJ4ZK+NQX7BnxZ8NM2KfNjvGtZB9gAAAAAAAAAAAAAAAAAAAA5XP+b12O28lJ/wARkjSkeEeIKPMzMzM8ZnjMgAAAAAAAAgEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7XT3O52eSNvmt/h7zwmfpme/wBQLnExMRMTrE8YmAAAAAAAAAAAAAAAAAAAAavMuYYdjtrZsk8eylO+0goe93mbebm+fLOtrTwjwjwgGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFg6f6h/l4rtN1OuHXSmT9Ovj6AWytq2rFqzFqz2THGASAAAAAAAAAAAAAAAADW5hzHbbHBOXNbj9NI+a0+gFG5nzLPv9xObJwrHClI7KwDUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1+TdQ59jMYssTl2093fX1AuO23W33WKMuC8XpPfH5gygAAAAAAAAAAAAAA5nNue7XYV8v9pnnsxxPZ6wU3e77c7zNOXPbzWnsjuiPCAa4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANjZcw3WzyefBea8fir3T64BcOT87nf/AAXw2x5NNfNETNJ9oOqAAAAAAAAAAACL3ilLXnsrGs6AqvNeqNxbzYdrS2GO/Jbhb2R3Ar172vab3mbWtxm08ZkEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaeAOpy/p7f7zS01+1i/Xbh7oBYtl0zy7b/Fev3r+N+z3A61KUpWK0iK1jsiOEAkAAAAAAAAAAAAGtuuXbLdRMZ8VbTMaebTj7wcHf9IaVm+zvrP93f8AKQV7c7Tcba80zY5paPGAYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdDlvJN7vrVmlfLhmeOW3Zp6PEFq5f0/sNnEW8v3csfXfj7oB0/UAAAAAAAAAAAAAAAAADFuNrt9xSaZscXrPjAK5zTpOYicmxnXjxxW/KQVzLiy4ck48tZpevbWe0HyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6x4smW8Y8dZte3CKwC0co6WpTy5t78V+2MXdHr8QWKtK0rFaRFaxwiI7ASAAAAAAAAAAAAAAAAAAAADT5hyrZ76k1zU+PuyR80e0FP5pyTdbC+to8+GflyR+YOcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADZ2HL9zvs32sFdf1WnsiPSC68q5NtuX4/h+PNMfHkmOM+oG+AAAAAAAAAAAAAAAAAAAAAAACL0pes1vEWrMaTEgqnOumbYtdxsom2Ptti749XoBXgAQCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb3KuU5+YZorWNMUfPk7oBd9lsdvssEYcFdIj5rd8z4yDYAAAAAAAAAAAAAAAAAAAAAAAAAABXufdO0yxbdbSvly9t8cdk+mAVS1Zraa2jS0cJiQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADf5RynLzDcRWNa4a8cmTwgF5222w7bDXDhr5cdeyPzkGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAHC6h5DXc0tutvGm4rxvWPrj+kFPms1mYmNJjhMAAAAAgEgAAAAAAAAAAAAAAAAAAAAAAA2+Wcuzb/c1w4+Fe29+6IBe9ns8G0wVw4Y0rWOM98z4yDOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACu9R8ijJW2821f3Kxrkxx3x4wCqAAAAAAAAAAAAAAAAAAAAAAAAAAAAybfBl3GamHFHmvedIgF85VyzDsNtXHSNbzxyX75kG6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMRMaTxgFQ6l5LG2v/N4K/s3n9ysdlZn+kHBAAAAAAAAAAAAAAAAAAAAAAAAAA9QLl03yf8AlcP8zmjTPkjhE/TUHbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8ZsVM2K2LJGtLxpaPRIKHzjlmTl+6nHOs4rccVvGAaIAAAAAAAAAAAAAAIBIAIBIAAAAAO101yn+a3H38tf2MU66THC1vAFz7I0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoc55ZTf7S1NIjLXjjtpxifD2goeTHfHe1LxNbVnS0T4wD5BAAJAAAAAAAAAAAAAAAAAAABk223ybjPTDjjW15iIB6DsNnj2e1x7enGKRxnxnvkGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq9V8r8l432P5bzpljwnxBXAQCQAAAAAAAAAAAAAAAQCQAAAWnpPlkRSd9kj4p1ri9XfILIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFutti3OC+DLGtLxpIPPt9tL7TdZMF+2k6RPjHdIMAAAAAAAAAAAAAAAAAAAAAM+x2l93u8e3p23nSZ8I75B6Hgw0w4aYscaUpEVrHqB9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArnV3LvPipvaR8VPhy+qeyQVUAAAAAAAAAAAAAAAAAAAAFn6P2MxGXeWiNJ/bxz3/1pBZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfG4w0zYL4bxrXJWazE+kHnO52+Tb58mHJwvjtNZ9gMYAAAAAAAAAAAAAAAAAAPrHS2S9aV+a0xWPXPAHomx2tdrtMW3idft1iNfGe8GcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFT6v2Xk3GPd17MkeS0emvZ/AFeAAAABAJAAAAAAAAAAAAB2Ol9n9/mUZLRE0wR5uPjPCAXUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjzvaRuuW5sekeaI81NfGvEFAAAAAAAAAAAAAAAAAAABc+lNp9nl33Zj4s8+b2RwgHaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmNeAPPucbWdrzHNi00r5vNX1W4g0wAAAAAAAAAAAAAAAAfWPHbJkrjr815iI9oPR9rhrh2+PFXspWI90AyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq3WO10yYdzEcLRNLezjAK2AAAAAAAAAAAAAAAADpdPbf7/NcMTHw0nzz7AXsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK6l2/3uVZJiJm2PS8aegFHAAAAAAAAAAAAAAAABY+jcGuXPmn6Yise3iC1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx7nHGXb5Mc9lqzH8Aeb3rNL2rPbWZifYCAAAAAAAAAAAAAAAAXPpPD9vlnnnty3mfdwB2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAefc5w/Z5nuKd3nmY9vEGmAAAAAAAAAAAAAAAD0Dk2L7XK9vX+pEzr6QboAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKX1Zi8nNPNH10ifcDjAAAAAAAAAAAAAAAmtfNaK+M6A9I29Ipt8dYjSK1iP4AyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq3WWPTLt8kR21msyCtgAAAAAAAAAAAAAAy7Snn3WGvjev4g9IiNIiI7IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABXusseu2wX74vMe+AVMAAAAAAAAAAAAAAG1yvy/wCY7fzdnnjtB6GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADh9X+X/Lqa9vnjQFOAAAAAAAB//Z"
+export const LoginBg = "../Layout/LoginBg.jpg";
+
+export const BaseURL = "https://64df594871c3335b25827869.mockapi.io/"
+
+
+
+export const convert_data_to_select = (array = []) => {
+ if (typeof array === 'undefined' || !Array.isArray(array)) {
+ throw new Error("Expected an array argument")
+ }
+ let new_array :any = []
+ array.map((e:any) => new_array.push({ label: e?.name, value: e?.id }))
+
+ return new_array
+ }
+
+ export const FakeSelectData :any = [
+ {
+ name : "mhmad",
+ id : 1
+ },
+ {
+ name : "karim",
+ id : 2
+ },
+ {
+ name : "suliman",
+ id : 3
+ },
+ {
+ name : "ibrahim",
+ id : 4
+ },
+]
+
+
+export const hasValue = (fieldValue: any, name: string): boolean => {
+ if (Array.isArray(fieldValue)) {
+ return fieldValue.length > 0;
+ } else if (typeof fieldValue === "object") {
+ return Object.keys(fieldValue).length > 0;
+ } else {
+
+ return !!fieldValue;
+ }
+};
\ No newline at end of file
diff --git a/src/Layout/app/ErrorPage.tsx b/src/Layout/app/ErrorPage.tsx
new file mode 100644
index 0000000..c8ce7f0
--- /dev/null
+++ b/src/Layout/app/ErrorPage.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { Button, Result } from 'antd';
+import { useTranslation } from 'react-i18next'; // Import useTranslation hook
+import { useLocation, useNavigate } from 'react-router-dom';
+
+import { useQueryClient } from 'react-query';
+const ErrorPage: React.FC = () => {
+ const { t } = useTranslation(); // Initialize useTranslation hook
+ const naviagate = useNavigate()
+ const location = useLocation();
+ const queryClient = useQueryClient(); // Initialize useQueryClient hook
+
+
+ const handleRefetch = () => {
+
+ const firstPath = location.pathname.split('/')[1]; // Get the first path segment from the URL
+ console.log(firstPath,"firstPath");
+
+ queryClient.invalidateQueries(firstPath === "/" ? 'home' : firstPath);
+ };
+
+ const handleGoToLogin = () => {
+ naviagate("/")
+ };
+
+ return (
+
+ {t('errorPage.refetch')} {/* Translate button text */}
+ ,
+ ,
+ ]}
+ >
+
+
+ );
+};
+
+export default ErrorPage;
diff --git a/src/Layout/app/Etaxi.tsx b/src/Layout/app/Etaxi.tsx
new file mode 100644
index 0000000..dd85aa4
--- /dev/null
+++ b/src/Layout/app/Etaxi.tsx
@@ -0,0 +1,41 @@
+import React from 'react'
+
+const Etaxi = () => {
+ return (
+
+
+ )
+}
+
+export default Etaxi
\ No newline at end of file
diff --git a/src/Layout/app/Export.tsx b/src/Layout/app/Export.tsx
new file mode 100644
index 0000000..c6dea28
--- /dev/null
+++ b/src/Layout/app/Export.tsx
@@ -0,0 +1,11 @@
+import DashHeader from '../../Layout/Dashboard/DashHeader';
+import LyTable from '../Dashboard/LyTable';
+import LayoutModal from '../Dashboard/LayoutModal'
+
+
+
+export {
+ DashHeader,
+ LyTable,
+ LayoutModal
+}
\ No newline at end of file
diff --git a/src/Layout/app/Header.tsx b/src/Layout/app/Header.tsx
new file mode 100644
index 0000000..5abb651
--- /dev/null
+++ b/src/Layout/app/Header.tsx
@@ -0,0 +1,65 @@
+import React from 'react'
+import { UserImageURL } from './Const'
+import Translate from '../../Components/Utils/Translate'
+import { useTranslation } from 'react-i18next'
+import { useNavigate } from 'react-router-dom';
+import useAuthState from '../../lib/state mangment/AuthState';
+import { GiHamburgerMenu } from 'react-icons/gi';
+import WithDrawer from './WithDrawer';
+import Sidebar from './SideBar';
+import { Dropdown, type MenuProps } from 'antd';
+
+
+const Header = () => {
+
+
+ const [t] = useTranslation();
+ const navigate = useNavigate()
+
+ const { logout , user} = useAuthState()
+ const handelClick = () => {
+ logout()
+ navigate('/auth')
+ }
+
+
+ const items: MenuProps['items'] = [
+ {
+ key: '1',
+ label: (
+ {t("Log Out")}
+ ),
+ },
+ ];
+
+ return (
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+ )
+}
+
+export default Header
\ No newline at end of file
diff --git a/src/Layout/app/KarimLogo.tsx b/src/Layout/app/KarimLogo.tsx
new file mode 100644
index 0000000..6c147ee
--- /dev/null
+++ b/src/Layout/app/KarimLogo.tsx
@@ -0,0 +1,54 @@
+import React from 'react'
+
+const KarimLogo = () => {
+ return (
+<>
+
+>
+ )
+}
+
+export default KarimLogo
\ No newline at end of file
diff --git a/src/Layout/app/Layout.tsx b/src/Layout/app/Layout.tsx
new file mode 100644
index 0000000..ca21133
--- /dev/null
+++ b/src/Layout/app/Layout.tsx
@@ -0,0 +1,39 @@
+import React, { useEffect } from 'react'
+import SideBar from './SideBar'
+import Header from './Header'
+import { useNavigate } from 'react-router-dom'
+import useAuthState from '../../lib/state mangment/AuthState'
+
+const Layout = ({ children }: { children: React.ReactNode }) => {
+
+
+ const navigate = useNavigate()
+ const { isAuthenticated } = useAuthState()
+ useEffect(() => {
+ if (!isAuthenticated) {
+
+ navigate('/auth')
+ }
+ }, [navigate])
+ return (
+ <>
+
+ >
+ )
+}
+
+export default Layout
\ No newline at end of file
diff --git a/src/Layout/app/LoadingPage.tsx b/src/Layout/app/LoadingPage.tsx
new file mode 100644
index 0000000..45d436f
--- /dev/null
+++ b/src/Layout/app/LoadingPage.tsx
@@ -0,0 +1,13 @@
+import React from 'react'
+import LoadingSpinner from '../../Components/Ui/LoadingSpinner'
+import { Spin } from 'antd'
+
+function LoadingPage() {
+ return (
+
+
+
+ )
+}
+
+export default LoadingPage
\ No newline at end of file
diff --git a/src/Layout/app/NotFoundPage.tsx b/src/Layout/app/NotFoundPage.tsx
new file mode 100644
index 0000000..316349a
--- /dev/null
+++ b/src/Layout/app/NotFoundPage.tsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import { useNavigate } from 'react-router-dom'
+
+function NotFoundPage() {
+ const navigate = useNavigate()
+ return (
+
+
+
+
404
|
This page could not be found
+
+
+
+ )
+}
+
+export default NotFoundPage
\ No newline at end of file
diff --git a/src/Layout/app/SideBar.tsx b/src/Layout/app/SideBar.tsx
new file mode 100644
index 0000000..c4e2b9a
--- /dev/null
+++ b/src/Layout/app/SideBar.tsx
@@ -0,0 +1,116 @@
+import React, { useEffect, useState } from 'react';
+import { FaAngleDown, FaAngleRight } from 'react-icons/fa';
+import { GiHamburgerMenu } from 'react-icons/gi';
+import { Link, useLocation } from 'react-router-dom';
+import { RoutesLinks } from '../../Routes';
+import { useTranslation } from 'react-i18next';
+import KarimLogo from './KarimLogo';
+import { useWindowSize } from '../../Hooks/useWindowSize';
+import Etaxi from './Etaxi';
+import { usePageState } from '../../lib/state mangment/LayoutPagestate';
+
+interface SidebarProps {}
+
+const Sidebar: React.FC = () => {
+ const { pathname } = useLocation();
+ // const {isOpenAddModel ,isOpenEditModel} = usePageState(state => state)
+ // useEffect(() => {
+ // if(isOpenAddModel || isOpenEditModel){
+ // setIsOpenSide(true);
+ // document.getElementById('DashboardLayout_Body')?.classList.add('DashboardLayout_Body_Open');
+ // }
+
+
+
+ // }, [isOpenAddModel ,isOpenEditModel])
+
+
+
+ const [isOpenSide, setIsOpenSide] = useState(false);
+ const [openDropdown, setOpenDropdown] = useState(null);
+ const [t] = useTranslation();
+ const windowSize = useWindowSize()
+
+ const handleHamburgerMenu = () => {
+ setIsOpenSide(true);
+ document.getElementById('DashboardLayout_Body')?.classList.add('DashboardLayout_Body_Open');
+ };
+
+ const handleImg = () => {
+ setIsOpenSide(false);
+ document.getElementById('DashboardLayout_Body')?.classList.remove('DashboardLayout_Body_Open');
+ setOpenDropdown(null);
+ };
+
+ const handleDropdown = (index: number) => {
+ setOpenDropdown((prev) => (prev === index ? null : index));
+ };
+
+ return (
+
+
+
+

+ {/*
*/}
+
+
+
+
+
+
+ {RoutesLinks?.map((item: any, index: number) => {
+ const isActive = pathname === item?.href;
+ const isDropdownOpen = openDropdown === index;
+
+ if (item?.hidden) {
+ return null;
+ }
+
+ if (item?.href ) {
+ return (
+
+ {React.cloneElement(item.icon, { size: 30 })}
+
{t(`${item?.name}`)}
+
+ );
+ } else {
+ return (
+
+ handleDropdown(index)}
+ className={
+ isDropdownOpen
+ ? 'SideBar_Link DropDown DropDown_SideBar_Link Open'
+ : 'SideBar_Link DropDown'
+ }
+ >
+ {React.cloneElement(item.icon, { size: 30 })}
+
{t(`${item?.name}`)}
+
{isDropdownOpen ? : }
+
+ {isDropdownOpen &&
+ item?.children?.map((child: any, childIndex: number) => {
+ if (child?.href) {
+ return (
+
+ {React.cloneElement(child.icon, { size: 30 })}
+ {t(`${child?.name}`)}
+
+ );
+ }
+ return null;
+ })}
+
+ );
+ }
+ })}
+
+
+ );
+};
+
+export default Sidebar;
diff --git a/src/Layout/app/Types.tsx b/src/Layout/app/Types.tsx
new file mode 100644
index 0000000..b8a4dc7
--- /dev/null
+++ b/src/Layout/app/Types.tsx
@@ -0,0 +1,19 @@
+export interface FormTableState {
+ objectToEdit: any[];
+ OpenEdit: boolean;
+ OpenAdd: boolean;
+ }
+
+ export type ValidationFieldProps = {
+ name: string;
+ name2?: string;
+ type: string;
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ option?: any;
+ isMulti?: boolean;
+ Disabled?: boolean;
+ group ? : boolean;
+ dir?:'rtl' | 'ltr'
+ };
\ No newline at end of file
diff --git a/src/Layout/app/WithDrawer.tsx b/src/Layout/app/WithDrawer.tsx
new file mode 100644
index 0000000..2c788a1
--- /dev/null
+++ b/src/Layout/app/WithDrawer.tsx
@@ -0,0 +1,53 @@
+import React, { useState, ReactNode } from 'react';
+import type { DrawerProps } from 'antd';
+import { Drawer, Space } from 'antd';
+
+interface WithDrawerProps {
+ button: React.ReactNode;
+ children: ReactNode;
+ className?:string
+}
+
+const WithDrawer: React.FC = ({ button, children,className }) => {
+ const [open, setOpen] = useState(false);
+ const [placement, setPlacement] = useState('left');
+
+ let What_the_language = localStorage.getItem('language') ?? "en";
+
+
+ return (
+ <>
+
+ {React.cloneElement(button as React.ReactElement, {
+ onClick: () => setOpen(true),
+ })}
+
+ setOpen(false)}
+ open={open}
+ key={What_the_language}
+ width="260"
+
+
+
+ >
+
+ {children}
+
+
+
+ >
+ );
+};
+
+export default WithDrawer;
+
+
+// Open}
+// >
+// {/* Your content goes here */}
+//
\ No newline at end of file
diff --git a/src/Pages/Auth/LoginForm.tsx b/src/Pages/Auth/LoginForm.tsx
new file mode 100644
index 0000000..8e1bbac
--- /dev/null
+++ b/src/Pages/Auth/LoginForm.tsx
@@ -0,0 +1,85 @@
+import React from 'react'
+import { Formik, Form, Field } from 'formik';
+import Translate from '../../Components/Utils/Translate';
+import { useTranslation } from 'react-i18next';
+import { useLoginAdmin } from '../../api/auth';
+
+import * as Yup from "yup";
+import { getInitialValues, getValidationSchema } from './formUtil';
+import { LoadingButton } from '../../Components/Ui/LoadingButton';
+import useNavigateOnSuccess from '../../Hooks/useNavigateOnSuccess';
+import useAuthState from '../../lib/state mangment/AuthState';
+import ValidationField from '../../Components/ValidationField/ValidationField';
+
+const LoginForm = () => {
+ const [t] = useTranslation();
+
+ const {mutate , isLoading , isSuccess, data} = useLoginAdmin()
+ const {login} = useAuthState()
+const OnSuccess = ()=>{
+
+}
+console.log(data,"data");
+
+ useNavigateOnSuccess(isSuccess , '/' , ()=>login(data as any ))
+
+ const handelSubmit = (values:any)=>{
+
+ console.log(values);
+ mutate(values)
+ // Implemnt Your Auth Code
+ }
+
+ return (
+
+

+
+
+
+
+
+
+
+
+ )
+}
+
+export default LoginForm
\ No newline at end of file
diff --git a/src/Pages/Auth/Page.tsx b/src/Pages/Auth/Page.tsx
new file mode 100644
index 0000000..91e6c7e
--- /dev/null
+++ b/src/Pages/Auth/Page.tsx
@@ -0,0 +1,32 @@
+import React, { useEffect } from 'react'
+import LoginForm from './LoginForm';
+import { LoginBg } from '../../Layout/app/Const';
+import useAuthState from '../../lib/state mangment/AuthState';
+import { useNavigate } from 'react-router-dom';
+const Auth = () => {
+
+ const { isAuthenticated } = useAuthState();
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ if (isAuthenticated) {
+ navigate('/')
+ }
+ }, [])
+
+ return (
+
+
+
+

+
+
+
+
+
+
+
+ )
+}
+
+export default Auth
\ No newline at end of file
diff --git a/src/Pages/Auth/formUtil.ts b/src/Pages/Auth/formUtil.ts
new file mode 100644
index 0000000..1eebde0
--- /dev/null
+++ b/src/Pages/Auth/formUtil.ts
@@ -0,0 +1,36 @@
+
+import * as Yup from "yup";
+import { buildFormData } from "../../api/helper/buildFormData";
+
+interface formUtilCommon {
+ password:string,
+ email:string
+}
+
+
+interface InitialValues extends formUtilCommon {
+
+}
+interface ValidateSchema extends formUtilCommon{
+
+}
+
+export const getInitialValues = (): InitialValues => {
+
+
+ return {
+ password: "",
+ email:""
+ }
+
+
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // validate input
+ return Yup.object().shape({
+ email:Yup.string().required("required"),
+ password:Yup.string().required("required"),
+
+ });
+};
\ No newline at end of file
diff --git a/src/Pages/Categories/Page.tsx b/src/Pages/Categories/Page.tsx
new file mode 100644
index 0000000..bd6d513
--- /dev/null
+++ b/src/Pages/Categories/Page.tsx
@@ -0,0 +1,46 @@
+
+import React from 'react'
+import DashBody from '../../Layout/Dashboard/DashBody'
+import DashHeader from '../../Layout/Dashboard/DashHeader'
+import LyTable from '../../Layout/Dashboard/LyTable'
+import useTableColumns from './useTableColumns'
+import { QueryStatusEnum } from '../../config/QueryStatus'
+import { useNavigate } from 'react-router-dom'
+import AddButton from '../../Layout/Dashboard/AddButton/AddButton'
+import { useGetCategories } from '../../api/Categories'
+import SearchField from '../../Layout/Dashboard/SearchField'
+
+function Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGetCategories()
+
+ const navigate = useNavigate()
+ const totalRows = data?.meta?.total;
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Page
+
diff --git a/src/Pages/Categories/View/AddForm.tsx b/src/Pages/Categories/View/AddForm.tsx
new file mode 100644
index 0000000..6a090a4
--- /dev/null
+++ b/src/Pages/Categories/View/AddForm.tsx
@@ -0,0 +1,37 @@
+
+import React, { useEffect } from 'react'
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+import { useGetRestaurant } from '../../../api/Restaurant';
+import useFormatToSelect from '../../../Hooks/useFormatToSelect';
+
+function Form() {
+ const {data:Restaurant} = useGetRestaurant()
+ const SelectRestaurantData = useFormatToSelect(Restaurant?.data)
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Categories/View/AddPage.tsx b/src/Pages/Categories/View/AddPage.tsx
new file mode 100644
index 0000000..0c84909
--- /dev/null
+++ b/src/Pages/Categories/View/AddPage.tsx
@@ -0,0 +1,52 @@
+import React, { useEffect, useState } from 'react'
+import { getInitialValues,getValidationSchema } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { useTranslation } from 'react-i18next';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import { useAddCategories } from '../../../api/Categories';
+import Form from './AddForm';
+
+const AddCategoriesPage = () => {
+
+
+ const { mutate, isLoading:IsloadingButton, isSuccess } = useAddCategories()
+ const handleSubmit = (values: any) => {
+ mutate(values);
+ };
+
+
+ const { t } = useTranslation();
+
+ useNavigateOnSuccess(isSuccess, '/Categories')
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, handleSubmit,IsloadingButton };
+
+
+ return (
+
+
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default AddCategoriesPage
\ No newline at end of file
diff --git a/src/Pages/Categories/View/EditForm.tsx b/src/Pages/Categories/View/EditForm.tsx
new file mode 100644
index 0000000..6a090a4
--- /dev/null
+++ b/src/Pages/Categories/View/EditForm.tsx
@@ -0,0 +1,37 @@
+
+import React, { useEffect } from 'react'
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+import { useGetRestaurant } from '../../../api/Restaurant';
+import useFormatToSelect from '../../../Hooks/useFormatToSelect';
+
+function Form() {
+ const {data:Restaurant} = useGetRestaurant()
+ const SelectRestaurantData = useFormatToSelect(Restaurant?.data)
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Categories/View/EditPage.tsx b/src/Pages/Categories/View/EditPage.tsx
new file mode 100644
index 0000000..f74b5a2
--- /dev/null
+++ b/src/Pages/Categories/View/EditPage.tsx
@@ -0,0 +1,74 @@
+import React, { useEffect, useState } from 'react'
+import { getInitialValues } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { Rate, Spin } from 'antd';
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetOneCategories, useUpdateCategories } from '../../../api/Categories';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const { data,isRefetching } = useGetOneCategories()
+ const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateCategories("put")
+ const handleSubmit = (values: any) => {
+ if( typeof values?.image === "string" ){
+ delete values["image"]
+ }
+
+ mutate({...values, _method : "put"});
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/Categories')
+
+
+ useEffect(() => {
+
+ setObjectToEdit(data?.data);
+
+ }, [data]);
+
+
+ const getValidationSchema = () => {
+ return null
+ };
+ if ( !objectToEdit || isRefetching) {
+ return
+ }
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, handleSubmit,IsloadingButton };
+
+
+ return (
+
+ {objectToEdit && data ?
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+ :
}
+
+
+
+ )
+
+}
+
+export default EditPage
\ No newline at end of file
diff --git a/src/Pages/Categories/formUtil.ts b/src/Pages/Categories/formUtil.ts
new file mode 100644
index 0000000..2510793
--- /dev/null
+++ b/src/Pages/Categories/formUtil.ts
@@ -0,0 +1,22 @@
+
+import * as Yup from "yup";
+
+
+export const getInitialValues = (objectToEdit: any | null = null): any => {
+ return {
+ id: objectToEdit?.id ?? null,
+ name: objectToEdit?.name ?? null,
+ image: objectToEdit?.image ?? null,
+ restaurant_id: objectToEdit?.restaurant_id ?? null,
+
+ };
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // Validate input
+ return Yup.object().shape({
+ name: Yup.string().required('Required'),
+
+ });
+};
+
diff --git a/src/Pages/Categories/useTableColumns.tsx b/src/Pages/Categories/useTableColumns.tsx
new file mode 100644
index 0000000..609f757
--- /dev/null
+++ b/src/Pages/Categories/useTableColumns.tsx
@@ -0,0 +1,71 @@
+
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../Components/Ui/tables/Actions";
+import ColumnsImage from "../../Components/Columns/ColumnsImage";
+import { useNavigate } from "react-router-dom";
+import { useDeleteCategories } from "../../api/Categories";
+import { MdEmail } from "react-icons/md";
+import { useModalState } from "../../zustand/Modal";
+
+function fnDelete(props :any ){}
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+ const deleteMutation = useDeleteCategories()
+ const navigate = useNavigate()
+ const {setIsOpen} = useModalState(state=>state)
+ return useMemo(
+ () => [
+
+ {
+ name: t("id"),
+ sortable: true, // Enable sorting for id column
+ center: true,
+ selector: (row: any) => row.id, // Specify selector function for sorting
+ }, {
+ name: t("name"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.name
+ },
+ {
+ name: t("image"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => {
+ let str = row?.image;
+ return
+ }
+
+ },
+ {
+ name: t("meals_count"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.meals_count
+ },
+
+ {
+ name: "#",
+ sortable: false,
+ center: true,
+ cell: (row:any) => (
+ navigate(`${row.id}`) }
+ showView={false}
+ onDelete={() => deleteMutation.mutate({ id: row.id })}
+ >
+
+ ),
+ },
+
+ ],
+ [t]
+ );
+};
+
+export default useTableColumns;
+
diff --git a/src/Pages/Meal/Page.tsx b/src/Pages/Meal/Page.tsx
new file mode 100644
index 0000000..738bb44
--- /dev/null
+++ b/src/Pages/Meal/Page.tsx
@@ -0,0 +1,46 @@
+
+import React from 'react'
+import DashBody from '../../Layout/Dashboard/DashBody'
+import DashHeader from '../../Layout/Dashboard/DashHeader'
+import LyTable from '../../Layout/Dashboard/LyTable'
+import useTableColumns from './useTableColumns'
+import { QueryStatusEnum } from '../../config/QueryStatus'
+import { useNavigate } from 'react-router-dom'
+import AddButton from '../../Layout/Dashboard/AddButton/AddButton'
+import { useGetMeal } from '../../api/Meal'
+import SearchField from '../../Layout/Dashboard/SearchField'
+
+function Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGetMeal()
+
+ const navigate = useNavigate()
+ const totalRows = data?.meta?.total;
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Page
+
diff --git a/src/Pages/Meal/View/AddForm.tsx b/src/Pages/Meal/View/AddForm.tsx
new file mode 100644
index 0000000..0fcb090
--- /dev/null
+++ b/src/Pages/Meal/View/AddForm.tsx
@@ -0,0 +1,41 @@
+
+import React, { useEffect } from 'react'
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+import { useGetCategories } from '../../../api/Categories';
+import useFormatToSelect from '../../../Hooks/useFormatToSelect';
+
+function Form() {
+ const {data:Categories} = useGetCategories()
+ const SelectCategoriesData = useFormatToSelect(Categories?.data)
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Meal/View/AddPage.tsx b/src/Pages/Meal/View/AddPage.tsx
new file mode 100644
index 0000000..4623a47
--- /dev/null
+++ b/src/Pages/Meal/View/AddPage.tsx
@@ -0,0 +1,52 @@
+import React, { useEffect, useState } from 'react'
+import { getInitialValues,getValidationSchema } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { useTranslation } from 'react-i18next';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import { useAddMeal } from '../../../api/Meal';
+import Form from './AddForm';
+
+const AddMealPage = () => {
+
+
+ const { mutate, isLoading:IsloadingButton, isSuccess } = useAddMeal()
+ const handleSubmit = (values: any) => {
+ mutate(values);
+ };
+
+
+ const { t } = useTranslation();
+
+ useNavigateOnSuccess(isSuccess, '/Meal')
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, handleSubmit,IsloadingButton };
+
+
+ return (
+
+
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default AddMealPage
\ No newline at end of file
diff --git a/src/Pages/Meal/View/EditForm.tsx b/src/Pages/Meal/View/EditForm.tsx
new file mode 100644
index 0000000..0fcb090
--- /dev/null
+++ b/src/Pages/Meal/View/EditForm.tsx
@@ -0,0 +1,41 @@
+
+import React, { useEffect } from 'react'
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+import { useGetCategories } from '../../../api/Categories';
+import useFormatToSelect from '../../../Hooks/useFormatToSelect';
+
+function Form() {
+ const {data:Categories} = useGetCategories()
+ const SelectCategoriesData = useFormatToSelect(Categories?.data)
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Meal/View/EditPage.tsx b/src/Pages/Meal/View/EditPage.tsx
new file mode 100644
index 0000000..ca7a1f4
--- /dev/null
+++ b/src/Pages/Meal/View/EditPage.tsx
@@ -0,0 +1,74 @@
+import React, { useEffect, useState } from 'react'
+import { getInitialValues } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { Rate, Spin } from 'antd';
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetOneMeal, useUpdateMeal } from '../../../api/Meal';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const { data,isRefetching } = useGetOneMeal()
+ const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateMeal("put")
+ const handleSubmit = (values: any) => {
+
+ if( typeof values?.image === "string" ){
+ delete values["video"]
+ }
+ mutate({...values, _method : "put"});
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/Meal')
+
+
+ useEffect(() => {
+
+ setObjectToEdit(data?.data);
+
+ }, [data]);
+
+
+ const getValidationSchema = () => {
+ return null
+ };
+ if ( !objectToEdit || isRefetching) {
+ return
+ }
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, handleSubmit,IsloadingButton };
+
+
+ return (
+
+ {objectToEdit && data ?
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+ :
}
+
+
+
+ )
+
+}
+
+export default EditPage
\ No newline at end of file
diff --git a/src/Pages/Meal/formUtil.ts b/src/Pages/Meal/formUtil.ts
new file mode 100644
index 0000000..6d5ef37
--- /dev/null
+++ b/src/Pages/Meal/formUtil.ts
@@ -0,0 +1,27 @@
+
+import * as Yup from "yup";
+
+
+export const getInitialValues = (objectToEdit: any | null = null): any => {
+ return {
+ id: objectToEdit?.id ?? null,
+ name: objectToEdit?.name ?? null,
+ images: objectToEdit?.images ?? null,
+ category_id: objectToEdit?.category_id ?? null,
+ video: objectToEdit?.video ?? null,
+ description: objectToEdit?.description ?? null,
+ price: objectToEdit?.price ?? null,
+ attributes: objectToEdit?.attributes ?? null,
+
+
+ };
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // Validate input
+ return Yup.object().shape({
+ name: Yup.string().required('Required'),
+
+ });
+};
+
diff --git a/src/Pages/Meal/useTableColumns.tsx b/src/Pages/Meal/useTableColumns.tsx
new file mode 100644
index 0000000..6c91cf2
--- /dev/null
+++ b/src/Pages/Meal/useTableColumns.tsx
@@ -0,0 +1,78 @@
+
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../Components/Ui/tables/Actions";
+import ColumnsImage from "../../Components/Columns/ColumnsImage";
+import { useNavigate } from "react-router-dom";
+import { useDeleteMeal } from "../../api/Meal";
+import { MdEmail } from "react-icons/md";
+import { useModalState } from "../../zustand/Modal";
+
+function fnDelete(props :any ){}
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+ const deleteMutation = useDeleteMeal()
+ const navigate = useNavigate()
+ const {setIsOpen} = useModalState(state=>state)
+ return useMemo(
+ () => [
+
+ {
+ name: t("id"),
+ sortable: true, // Enable sorting for id column
+ center: true,
+ selector: (row: any) => row.id, // Specify selector function for sorting
+ }, {
+ name: t("name"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.name
+ },
+ {
+ name: t("image"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => {
+ let str = row?.images?.[0]?.url;
+ return
+ }
+
+ },
+
+ {
+ name: t("description"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.description
+ },
+
+ {
+ name: t("price"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.price
+ },
+ {
+ name: "#",
+ sortable: false,
+ center: true,
+ cell: (row:any) => (
+ navigate(`${row.id}`) }
+ showView={false}
+ onDelete={() => deleteMutation.mutate({ id: row.id })}
+ >
+
+ ),
+ },
+
+ ],
+ [t]
+ );
+};
+
+export default useTableColumns;
+
diff --git a/src/Pages/Offer/Page.tsx b/src/Pages/Offer/Page.tsx
new file mode 100644
index 0000000..85f9231
--- /dev/null
+++ b/src/Pages/Offer/Page.tsx
@@ -0,0 +1,46 @@
+
+import React from 'react'
+import DashBody from '../../Layout/Dashboard/DashBody'
+import DashHeader from '../../Layout/Dashboard/DashHeader'
+import LyTable from '../../Layout/Dashboard/LyTable'
+import useTableColumns from './useTableColumns'
+import { QueryStatusEnum } from '../../config/QueryStatus'
+import { useNavigate } from 'react-router-dom'
+import AddButton from '../../Layout/Dashboard/AddButton/AddButton'
+import { useGetOffer } from '../../api/Offer'
+import SearchField from '../../Layout/Dashboard/SearchField'
+
+function Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGetOffer()
+
+ const navigate = useNavigate()
+ const totalRows = data?.meta?.total;
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Page
+
diff --git a/src/Pages/Offer/View/AddForm.tsx b/src/Pages/Offer/View/AddForm.tsx
new file mode 100644
index 0000000..c27fa6f
--- /dev/null
+++ b/src/Pages/Offer/View/AddForm.tsx
@@ -0,0 +1,39 @@
+
+import React, { useEffect } from 'react'
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+import { useGetRestaurant } from '../../../api/Restaurant';
+import useFormatToSelect from '../../../Hooks/useFormatToSelect';
+
+function Form() {
+ const {data:Restaurant} = useGetRestaurant()
+ const SelectRestaurantData = useFormatToSelect(Restaurant?.data)
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Offer/View/AddPage.tsx b/src/Pages/Offer/View/AddPage.tsx
new file mode 100644
index 0000000..695ed25
--- /dev/null
+++ b/src/Pages/Offer/View/AddPage.tsx
@@ -0,0 +1,52 @@
+import React, { useEffect, useState } from 'react'
+import { getInitialValues,getValidationSchema } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { useTranslation } from 'react-i18next';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import { useAddOffer } from '../../../api/Offer';
+import Form from './AddForm';
+
+const AddOfferPage = () => {
+
+
+ const { mutate, isLoading:IsloadingButton, isSuccess } = useAddOffer()
+ const handleSubmit = (values: any) => {
+ mutate(values);
+ };
+
+
+ const { t } = useTranslation();
+
+ useNavigateOnSuccess(isSuccess, '/Offer')
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, handleSubmit,IsloadingButton };
+
+
+ return (
+
+
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default AddOfferPage
\ No newline at end of file
diff --git a/src/Pages/Offer/View/EditForm.tsx b/src/Pages/Offer/View/EditForm.tsx
new file mode 100644
index 0000000..c27fa6f
--- /dev/null
+++ b/src/Pages/Offer/View/EditForm.tsx
@@ -0,0 +1,39 @@
+
+import React, { useEffect } from 'react'
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+import { useGetRestaurant } from '../../../api/Restaurant';
+import useFormatToSelect from '../../../Hooks/useFormatToSelect';
+
+function Form() {
+ const {data:Restaurant} = useGetRestaurant()
+ const SelectRestaurantData = useFormatToSelect(Restaurant?.data)
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Offer/View/EditPage.tsx b/src/Pages/Offer/View/EditPage.tsx
new file mode 100644
index 0000000..d26342d
--- /dev/null
+++ b/src/Pages/Offer/View/EditPage.tsx
@@ -0,0 +1,73 @@
+import React, { useEffect, useState } from 'react'
+import { getInitialValues } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { Rate, Spin } from 'antd';
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetOneOffer, useUpdateOffer } from '../../../api/Offer';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const { data,isRefetching } = useGetOneOffer()
+ const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateOffer("put")
+ const handleSubmit = (values: any) => {
+ if( typeof values?.image === "string" ){
+ delete values["image"]
+ }
+ mutate({...values, _method : "put"});
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/Offer')
+
+
+ useEffect(() => {
+
+ setObjectToEdit(data?.data);
+
+ }, [data]);
+
+
+ const getValidationSchema = () => {
+ return null
+ };
+ if ( !objectToEdit || isRefetching) {
+ return
+ }
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, handleSubmit,IsloadingButton };
+
+
+ return (
+
+ {objectToEdit && data ?
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+ :
}
+
+
+
+ )
+
+}
+
+export default EditPage
\ No newline at end of file
diff --git a/src/Pages/Offer/formUtil.ts b/src/Pages/Offer/formUtil.ts
new file mode 100644
index 0000000..89652cd
--- /dev/null
+++ b/src/Pages/Offer/formUtil.ts
@@ -0,0 +1,25 @@
+
+import * as Yup from "yup";
+
+
+export const getInitialValues = (objectToEdit: any | null = null): any => {
+ return {
+ id: objectToEdit?.id ?? null,
+ name: objectToEdit?.name ?? null,
+ image: objectToEdit?.images ?? null,
+ restaurant_id: objectToEdit?.restaurant?.id ?? null,
+ description: objectToEdit?.description ?? null,
+ price: objectToEdit?.price ?? null,
+
+
+ };
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // Validate input
+ return Yup.object().shape({
+ name: Yup.string().required('Required'),
+
+ });
+};
+
diff --git a/src/Pages/Offer/useTableColumns.tsx b/src/Pages/Offer/useTableColumns.tsx
new file mode 100644
index 0000000..6e7efe4
--- /dev/null
+++ b/src/Pages/Offer/useTableColumns.tsx
@@ -0,0 +1,78 @@
+
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../Components/Ui/tables/Actions";
+import ColumnsImage from "../../Components/Columns/ColumnsImage";
+import { useNavigate } from "react-router-dom";
+import { useDeleteOffer } from "../../api/Offer";
+import { MdEmail } from "react-icons/md";
+import { useModalState } from "../../zustand/Modal";
+
+function fnDelete(props :any ){}
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+ const deleteMutation = useDeleteOffer()
+ const navigate = useNavigate()
+ const {setIsOpen} = useModalState(state=>state)
+ return useMemo(
+ () => [
+
+ {
+ name: t("id"),
+ sortable: true, // Enable sorting for id column
+ center: true,
+ selector: (row: any) => row.id, // Specify selector function for sorting
+ }, {
+ name: t("name"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.name
+ },
+ {
+ name: t("image"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => {
+ let str = row?.images?.[0]?.url;
+ return
+ }
+
+ },
+
+ {
+ name: t("description"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.description
+ },
+
+ {
+ name: t("price"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.price
+ },
+ {
+ name: "#",
+ sortable: false,
+ center: true,
+ cell: (row:any) => (
+ navigate(`${row.id}`) }
+ showView={false}
+ onDelete={() => deleteMutation.mutate({ id: row.id })}
+ >
+
+ ),
+ },
+
+ ],
+ [t]
+ );
+};
+
+export default useTableColumns;
+
diff --git a/src/Pages/Setting/Map.tsx b/src/Pages/Setting/Map.tsx
new file mode 100644
index 0000000..86febcb
--- /dev/null
+++ b/src/Pages/Setting/Map.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
+import 'leaflet/dist/leaflet.css';
+
+const Map = ({lat,long}:any) => {
+ return (
+
+
+
+ );
+
+}
+
+export default Map
\ No newline at end of file
diff --git a/src/Pages/Setting/Page.tsx b/src/Pages/Setting/Page.tsx
new file mode 100644
index 0000000..1a68429
--- /dev/null
+++ b/src/Pages/Setting/Page.tsx
@@ -0,0 +1,96 @@
+import { Image, Spin } from "antd";
+import React from "react";
+import SimpleMap from "./Map";
+import { useGetOneSetting, useGetSetting } from "../../api/GuestApi";
+import { TOKEN_KEY } from "../../api/config";
+import useAuthState from "../../lib/state mangment/AuthState";
+import ReactPlayer from 'react-player'
+import { FaEdit } from "react-icons/fa";
+import { useNavigate } from "react-router-dom";
+
+const Page = () => {
+ const { token } = useAuthState();
+ console.log(token, "token");
+ const navigate= useNavigate()
+ const fake = "900310ff-610f-11ee-9fbc-00505649cf62";
+ const { data, isLoading } = useGetSetting({
+ show: fake,
+ });
+ console.log(data, "data");
+ const {
+ logo,
+ name,
+ address,
+ contact_info,
+ slogan,
+ attributes,
+ images,
+ video,
+ id
+
+ } = data?.data ?? [];
+ console.log(attributes, "attribute");
+
+ console.log(video,"video");
+
+ if(isLoading){
+ return
+ }
+ return (
+
+
+ {Object.entries(slogan).map(([key, value]:any, index) => {
+ console.log(key, value);
+ return (
+
+ {key} : {value}
+
+ );
+ })}
+
+
+
+
phone_number : {contact_info?.phone_number}
+ email : {contact_info?.email}
+ {Object.entries(attributes).map(([key, value]:any, index) => {
+ console.log(key, value);
+ return (
+
+ {key} : {value}
+
+ );
+ })}
+
+
+ {images?.map((item:any,index:number)=>{
+ return (
+
+ )
+ })}
+
+ {video &&
+
+
+ }
+
+
navigate(id)} >
+
+
+
+ );
+};
+
+export default Page;
diff --git a/src/Pages/Setting/View/EditForm.tsx b/src/Pages/Setting/View/EditForm.tsx
new file mode 100644
index 0000000..05d863d
--- /dev/null
+++ b/src/Pages/Setting/View/EditForm.tsx
@@ -0,0 +1,41 @@
+
+import React, { useEffect } from 'react'
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+import { useGetCategories } from '../../../api/Categories';
+import useFormatToSelect from '../../../Hooks/useFormatToSelect';
+
+function Form() {
+ const {data:Categories} = useGetCategories()
+ const SelectCategoriesData = useFormatToSelect(Categories?.data)
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Setting/View/EditPage.tsx b/src/Pages/Setting/View/EditPage.tsx
new file mode 100644
index 0000000..ca7a1f4
--- /dev/null
+++ b/src/Pages/Setting/View/EditPage.tsx
@@ -0,0 +1,74 @@
+import React, { useEffect, useState } from 'react'
+import { getInitialValues } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { Rate, Spin } from 'antd';
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetOneMeal, useUpdateMeal } from '../../../api/Meal';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const { data,isRefetching } = useGetOneMeal()
+ const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateMeal("put")
+ const handleSubmit = (values: any) => {
+
+ if( typeof values?.image === "string" ){
+ delete values["video"]
+ }
+ mutate({...values, _method : "put"});
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/Meal')
+
+
+ useEffect(() => {
+
+ setObjectToEdit(data?.data);
+
+ }, [data]);
+
+
+ const getValidationSchema = () => {
+ return null
+ };
+ if ( !objectToEdit || isRefetching) {
+ return
+ }
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, handleSubmit,IsloadingButton };
+
+
+ return (
+
+ {objectToEdit && data ?
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+ :
}
+
+
+
+ )
+
+}
+
+export default EditPage
\ No newline at end of file
diff --git a/src/Pages/Setting/formUtil.ts b/src/Pages/Setting/formUtil.ts
new file mode 100644
index 0000000..daff665
--- /dev/null
+++ b/src/Pages/Setting/formUtil.ts
@@ -0,0 +1,25 @@
+
+import * as Yup from "yup";
+
+
+export const getInitialValues = (objectToEdit: any | null = null): any => {
+ return {
+ id: objectToEdit?.id ?? null,
+ name: objectToEdit?.name ?? null,
+ images: objectToEdit?.images ?? null,
+ address: objectToEdit?.address ?? null,
+ contact_info: objectToEdit?.contact_info ?? null,
+ slogan: objectToEdit?.slogan ?? null,
+ video: objectToEdit?.video ?? null,
+ attributes: objectToEdit?.attributes ?? null,
+ };
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // Validate input
+ return Yup.object().shape({
+ name: Yup.string().required('Required'),
+
+ });
+};
+
diff --git a/src/ProviderContainer.tsx b/src/ProviderContainer.tsx
new file mode 100644
index 0000000..c30c964
--- /dev/null
+++ b/src/ProviderContainer.tsx
@@ -0,0 +1,24 @@
+import React, { ReactNode } from 'react'
+import QueryProvider from './lib/ReactQueryProvider'
+import { BrowserRouter } from 'react-router-dom'
+import ToastProvider from './lib/ToastProvider'
+import { createBrowserHistory } from 'history'
+
+type ProviderContainerProps = {
+ children:ReactNode
+
+}
+export let history = createBrowserHistory()
+function ProviderContainer({children}:ProviderContainerProps) {
+ return (
+
+
+
+ {children}
+
+
+
+ )
+}
+
+export default ProviderContainer
\ No newline at end of file
diff --git a/src/Routes.tsx b/src/Routes.tsx
new file mode 100644
index 0000000..347a723
--- /dev/null
+++ b/src/Routes.tsx
@@ -0,0 +1,123 @@
+import { ReactNode } from "react";
+
+// Icons Import
+import { FaHome } from "react-icons/fa"
+import { BiCategory, BiSolidCoupon, BiSolidOffer } from "react-icons/bi";
+
+
+// Pages Import
+
+
+import CategoriesPage from "./Pages/Categories/Page";
+import AddCategoriesPage from "./Pages/Categories/View/AddPage";
+import EditCategories from "./Pages/Categories/View/EditPage";
+
+import MealPage from "./Pages/Meal/Page";
+import AddMealPage from "./Pages/Meal/View/AddPage";
+import EditMeal from "./Pages/Meal/View/EditPage";
+
+
+import OfferPage from "./Pages/Offer/Page";
+import AddOfferPage from "./Pages/Offer/View/AddPage";
+import EditOffer from "./Pages/Offer/View/EditPage";
+
+import SettingPage from './Pages/Setting/Page'
+import SettingEditPage from './Pages/Setting/View/EditPage'
+
+
+import { SettingFilled } from "@ant-design/icons";
+import { GiMeal } from "react-icons/gi";
+
+
+
+
+
+
+
+interface RoutesLinksType {
+ name?: string,
+ href?: string,
+ element?: ReactNode,
+ icon?: any,
+ Viewelement?: ReactNode,
+ Viewhref?: string
+ children?: any
+ hidden?: boolean
+}
+export const RoutesLinks: RoutesLinksType[] = [
+
+ {
+ name: "Home",
+ element: <>Home Page>,
+ icon: ,
+ href: "/",
+ },
+
+
+
+
+ {
+ name: "Categories",
+ element: ,
+ icon: ,
+ href: "/Categories",
+ },
+ {
+ href: "/Categories/:id",
+ element: ,
+ hidden:true
+ },
+ {
+ href: "/Categories/add",
+ element: ,
+ hidden:true
+ },
+ {
+ name: "Meal",
+ element: ,
+ icon: ,
+ href: "/Meal",
+ },
+ {
+ href: "/Meal/:id",
+ element: ,
+ hidden:true
+ },
+ {
+ href: "/Meal/add",
+ element: ,
+ hidden:true
+ },
+
+ {
+ name: "Offer",
+ element: ,
+ icon: ,
+ href: "/Offer",
+ },
+ {
+ href: "/Offer/:id",
+ element: ,
+ hidden:true
+ },
+ {
+ href: "/Offer/add",
+ element: ,
+ hidden:true
+ },
+
+ {
+ name: "Setting",
+ element: ,
+ icon: ,
+ href: "/Setting",
+ },
+
+ {
+ name: "SettingEdit",
+ element: ,
+ href: "/Setting/:id",
+ hidden:true
+
+ },
+]
\ No newline at end of file
diff --git a/src/Styles/AppStyle/App.scss b/src/Styles/AppStyle/App.scss
new file mode 100644
index 0000000..d9efda0
--- /dev/null
+++ b/src/Styles/AppStyle/App.scss
@@ -0,0 +1,93 @@
+@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');
+
+
+html,body {
+ background: var(--bg2);
+ font-family: 'Poppins', sans-serif;
+
+}
+
+*{
+ padding: 0;
+ margin: 0;
+}
+
+a {
+ color: inherit;
+ font-weight: bold;
+ text-decoration: none !important;
+ cursor: pointer;
+
+}
+
+button,
+svg {
+ cursor: pointer;
+}
+
+
+
+
+
+
+.not_foound_page{
+ background: black;
+ height: 100vh;
+ display: flex;justify-content: center;align-items:center;
+
+
+ p{
+ color: white;
+ display: inline;
+
+ }
+ h6{
+ display: inline;
+ margin-inline:20px;
+ height: 140px !important;
+
+ width: 20px;
+ }
+ .container-not-found{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ div{
+ display: flex;justify-content: center;align-items: center;
+
+ }
+ button{
+ border: none;
+ outline: none;
+ padding: 8px;
+ border-radius: 10px;
+
+ margin-inline:30px;
+ }
+ }
+}
+
+.lock_icon{
+ color: var(--primary);
+ margin-left: 7px;
+}
+
+
+.primary {
+ color: var(--primary) !important;
+}
+
+
+.bg-primary {
+ background-color: var(--primary) !important;
+}
+.secondary {
+ color: var(--secondary) !important;
+}
+
+
+.bg-secondary {
+ background-color: var(--secondary) !important;
+}
+
+
diff --git a/src/Styles/AppStyle/Import.scss b/src/Styles/AppStyle/Import.scss
new file mode 100644
index 0000000..eed8ba0
--- /dev/null
+++ b/src/Styles/AppStyle/Import.scss
@@ -0,0 +1,23 @@
+
+@import './Varibils.scss';
+@import './Mixing.scss';
+@import './App.scss';
+@import '../Layout/Header.scss';
+@import '../Layout/Layout.scss';
+@import '../Layout/SideBar.scss';
+@import '../Auth/Auth.scss';
+@import '../Layout/Table.scss';
+
+@import '../component/printButton.scss';
+@import '../component/DarkStyle.scss';
+@import '../component/ErrorPage.scss';
+@import '../component/Tab_Info.scss';
+@import '../component/DriverInfoSocket.scss';
+@import '../component/radio.scss';
+
+@import '../Layout/FillterSection.scss';
+
+@import '../Home/Setting.scss';
+
+
+
diff --git a/src/Styles/AppStyle/Mixing.scss b/src/Styles/AppStyle/Mixing.scss
new file mode 100644
index 0000000..5641f40
--- /dev/null
+++ b/src/Styles/AppStyle/Mixing.scss
@@ -0,0 +1,21 @@
+
+@mixin Shadow {
+ box-shadow: 0 4px 20px 0 rgba(0, 0, 0, 0.05);
+
+}
+
+
+@mixin Flex {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+}
+
+
+
+
+@mixin GlassModeCover{
+ background-color: rgba(16 18 27 / 40%);
+ backdrop-filter: blur(24px);
+}
\ No newline at end of file
diff --git a/src/Styles/AppStyle/Varibils.scss b/src/Styles/AppStyle/Varibils.scss
new file mode 100644
index 0000000..ae6688b
--- /dev/null
+++ b/src/Styles/AppStyle/Varibils.scss
@@ -0,0 +1,36 @@
+:root {
+ --primary:#E57DB1 ;
+ --secondary : #2D9CDB;
+ --text: #565656;
+ --bg: #ffffff;
+ --bg2: #f8f8f8;
+ --shadow: rgba(0, 0, 0, 0.15);
+ --gray : rgb(207, 210, 214);
+ --linear : linear-gradient(118deg, #2D9CDB, #2D9CDB)
+}
+
+:root:has(.dark) {
+ --primary: #fcb04f ;
+ --secondary: #304a7e;
+ --text: #ffffff;
+ --bg: #1f1f1f;
+ --bg2: #2c2c2c;
+ --shadow: rgba(255, 255, 255, 0.15);
+ --gray: #a0aec0;
+ --linear : linear-gradient(118deg, #fcb04f, #f78c3f)
+
+
+}
+
+:root:has(.glass) {
+ --primary:white;
+ --secondary : #ffd12e;
+ --text: white;
+ --bg: ;
+ --bg2: ;
+ --shadow: rgba(0, 0, 0, 0.15);
+ --gray : rgb(207, 210, 214);
+ --linear :
+
+ }
+
diff --git a/src/Styles/Auth/Auth.scss b/src/Styles/Auth/Auth.scss
new file mode 100644
index 0000000..f2c8028
--- /dev/null
+++ b/src/Styles/Auth/Auth.scss
@@ -0,0 +1,156 @@
+.Auth{
+ // background: url('../../../public/Layout/LoginBg.jpg');
+
+ .In_Auth{
+ background-color: var(--bg);
+ display: flex;
+ justify-content: center; align-items: center;
+ gap: 30px;
+ height: 80vh;
+
+ }
+ .LoginForm{
+ display: flex; flex-direction: column;
+
+ .Login_Nav{
+ display: flex; justify-content: space-between ; align-items: center;
+ margin-bottom: 30px;
+ }
+ }
+ .Left_Col,.Right_Col{
+ padding-inline: 30px;
+ display: flex;
+ justify-content: center; align-items: center;
+ height: 100%;
+ width: 30vw;
+ }
+ .Left_Col{
+ background-color: #edf4f4;
+ }
+
+ .img-fluid{
+ width: 30vw;
+ height: 100%;
+ }
+ .Login_H4{
+ width: 90%;
+ font-size: 16px;
+ }
+ .Reserved{
+ transform:translatex(15px) translatey(44px);
+ }
+ .LoginForm{
+ .Logo{
+ display: none;
+ }
+ }
+ @media screen and (max-width: 800px) {
+ .Left_Col{
+ display: none;
+ }
+
+ .LoginForm{
+ .Logo{
+ // position: absolute;
+ display: block;
+ width: 150px;
+ transform: translate(80px ,-40px);
+
+ }
+ }
+ .Login_H4{
+ text-align: center ;
+ }
+ .Right_Col{
+ padding-inline: 30px;
+ display: flex;
+ justify-content: center; align-items: center;
+ width: 400px;
+ height: fit-content;
+ }
+ .In_Auth{
+
+ height: 550px !important;
+
+ }
+
+
+ }
+
+ @media screen and (max-width: 400px) {
+ .LoginForm{
+ .Logo{
+ // position: absolute;
+ display: block;
+ width: 120px;
+ transform: translate(50px ,-20px);
+
+ }
+ }
+ .Right_Col{
+ padding-inline: 30px;
+ display: flex;
+ justify-content: center; align-items: center;
+ width: 300px !important;
+ }
+ }
+
+
+}
+
+.Logo{
+ width: 100%;
+}
+
+.dark{
+ .Left_Col{
+ background-color: #343434;
+ }
+ .Login_H4, .Reserved{
+ color: #fff;
+ }
+ .Login_Nav{
+ h5{
+ color: #fff;
+ }
+ }
+}
+.glass{
+ .Left_Col{
+ background-color: inherit;
+ }
+ .Login_H4, .Reserved{
+ color: #000;
+ }
+ .Login_Nav{
+ h5{
+ color: #000;
+ }
+ }
+}
+
+
+.ar{
+ .LoginForm{
+ .Logo{
+ transform: translate(-90px ,-40px);
+ }
+ }
+}
+
+
+@media screen and (max-width:400px) {
+
+ .ar{
+ .LoginForm{
+ .Logo{
+ transform: translate(-70px ,-30px) !important;
+
+ }
+ }
+ }
+}
+
+.logo_link{
+ display: none !important;
+}
\ No newline at end of file
diff --git a/src/Styles/Home/Auth.scss b/src/Styles/Home/Auth.scss
new file mode 100644
index 0000000..bc8b1e6
--- /dev/null
+++ b/src/Styles/Home/Auth.scss
@@ -0,0 +1,16 @@
+// Auth
+// In_Auth
+// Left_Auth
+// Right_Auth
+
+.Auth{
+ height: 100vh;
+ max-width: 100vw;
+ display: flex; justify-content: center; align-items: center;
+ flex-direction: column;
+
+ .In_Auth{
+ width: 70vw;
+
+ }
+}
\ No newline at end of file
diff --git a/src/Styles/Home/Setting.scss b/src/Styles/Home/Setting.scss
new file mode 100644
index 0000000..7c3f073
--- /dev/null
+++ b/src/Styles/Home/Setting.scss
@@ -0,0 +1,37 @@
+.Personal_Image{
+ border-radius: 50%;
+}
+.SettingPage{
+ background: var(--bg);
+ @include Shadow;
+ border-radius: 40px;
+ padding: 20px 10%;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ position: relative;
+
+}
+.SettingPage_header{
+ display: flex;
+ gap: 20px;
+}
+.leaflet-control-attribution {
+ display: none !important;
+}
+.Personal_Images{
+ display: flex;
+ gap: 30px;
+ flex-wrap: wrap;
+
+
+}
+
+.EditButton{
+ position: absolute;
+ right: 40px;
+ top: 40px;
+ svg{
+ color: var(--primary);
+ }
+}
\ No newline at end of file
diff --git a/src/Styles/Layout/FillterSection.scss b/src/Styles/Layout/FillterSection.scss
new file mode 100644
index 0000000..aa7e1ee
--- /dev/null
+++ b/src/Styles/Layout/FillterSection.scss
@@ -0,0 +1,18 @@
+.FillterSection{
+
+ display: flex;
+ gap: 20px;
+ flex-wrap: wrap;
+ margin-bottom: 20px;
+ align-items: center;
+ flex-direction: row-reverse;
+ .SelectField{
+ width: 150px;
+ }
+}
+
+@media screen and (max-width: 600px) {
+ .SelectField{
+ display: none;
+ }
+ }
\ No newline at end of file
diff --git a/src/Styles/Layout/Header.scss b/src/Styles/Layout/Header.scss
new file mode 100644
index 0000000..84cd0b3
--- /dev/null
+++ b/src/Styles/Layout/Header.scss
@@ -0,0 +1,120 @@
+.Header{
+ width: 100%;
+ height: 65px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 30px;
+ background: var(--bg);
+ margin-top: 20px;
+ @include Shadow;
+ .Header_Left{
+ @include Flex;
+ gap: 5px;
+ border-radius: 5px;
+ padding-inline: 5px;
+ color: var(--primary);
+ font-weight: bolder;
+
+ }
+ svg{
+ margin-inline:10px;
+ }
+}
+.Header_Menu{
+
+ z-index: 9999999999999;
+
+}
+.szh-menu-button{
+ color: var(--text);
+ background: var(--bg);
+ border: none; outline: none;
+ padding: .6vw;
+ border-radius: 5px;
+}
+
+.szh-menu__item{
+ color: var(--text);
+ background: var(--bg);
+ &:hover{
+ background: var(--bg2);
+ }
+}
+.Header_Right{
+ padding-inline: 5px;
+ direction: ltr;
+ @include Flex ;
+ .Setting{
+
+ margin-inline: 1vw;
+ svg{
+ fill: var(--primary);
+ background: var(--bg2);
+ padding: 0.6vw;
+ border-radius: 5px;
+ }
+ }
+ .User_Pro{
+ margin-inline: 1vw;
+ @include Flex ;
+ gap: .5vw;
+ }
+}
+
+.szh-menu {
+ min-width: auto !important;
+}
+.UNK_User{
+ border-radius: 50%;
+ height: 40px;
+ aspect-ratio: auto 40 / 40;
+ width: 40px;
+
+}
+.User_info{
+ text-align: right;
+ display: flex;justify-content: center;align-items: flex-end; flex-direction: column;
+ text-align: start;
+ width: 100%;
+ h6,p{
+ width: 100%;
+ margin-bottom: 0;
+ font-size: .7rem;
+ }
+ h6{
+ text-align: start !important;
+ }
+ p{
+ opacity: .8;
+ }
+}
+.Translate{
+ display: flex; justify-content: center; align-items: center; margin-inline: 10px;
+ p{
+ opacity: .7;
+ margin-bottom: 0;
+ }
+}
+
+.Header_Left{
+ >*{
+ display: none;
+ }
+}
+@media screen and (max-width: 700px) {
+
+.Header_Left{
+ >*{
+ display: block;
+ }
+}
+}
+
+.ant-dropdown-link{
+ all: unset;
+}
+.MenuPropsItem{
+ display: flex;
+ gap: 10px;
+}
\ No newline at end of file
diff --git a/src/Styles/Layout/Layout.scss b/src/Styles/Layout/Layout.scss
new file mode 100644
index 0000000..9a63f31
--- /dev/null
+++ b/src/Styles/Layout/Layout.scss
@@ -0,0 +1,548 @@
+
+///// Layout
+.DashboardLayout {
+ color: var(--text); background: var(--bg2);
+ width: 100%;
+ background-size: cover;
+ background-position: center;
+ min-height: 100vh;
+ display: flex; justify-content: center; align-items: center;
+ .DashboardLayout_Cover{
+ min-height: 100vh;
+ width: 100vw;
+ border-radius: 20px;
+
+ }
+
+ .DashboardLayout_Body{
+ position: absolute;
+ left: 290px;
+ width: calc(98% - 290px);
+
+ }
+ .DashboardLayout_Body_Open{
+ left: 140px;
+ width: calc(98% - 140px);
+ transition: 1s ease-in-out;
+
+
+ }
+
+
+}
+///// Arabic Mood
+.ar{
+ .DashboardLayout_Body{
+ right: 290px;
+
+ }
+ .DashboardLayout_Body_Open{
+ right: 140px;
+ width: calc(96% - 140px);
+ transition: 1s ease-in-out;
+
+
+ }
+}
+
+
+
+.card {
+background: var(--bg);
+ @include Shadow;
+ outline: none !important;
+ border: none !important;
+}
+.Model_Button{
+ background: var(--primary);
+ outline: none;
+ border: none;
+}
+.SweetAlert{
+ .btn-primary{
+ background: var(--primary);
+ outline: none;
+ border: none;
+ box-shadow: none !important;
+ }
+}
+.TableActions{
+ svg{
+ fill: var(--primary);
+ }
+}
+.form-control:focus{
+ box-shadow: 0 0 0 0.2rem rgba(0, 0, 0, 0.2) !important;
+ border: var(--primary);
+}
+.Page_Header{
+ display: flex; justify-content: space-between;
+ margin-bottom: 20px;
+ // align-items: center ;
+
+ h1{
+ font-size: 30px;
+ font-weight: 600;
+
+ }
+}
+.PrimaryColor{
+ margin-inline: 10px;
+}
+
+.react-toggle-track{
+ background: red ;
+}
+
+///// spinner
+.jwoUqQ{
+ color: var(--primary) !important;
+}
+.Auth{
+ background-color: var(--bg2);
+ margin: auto;
+ width:100%;
+ display: flex; justify-content: center; align-items: center;
+ height: 100vh;
+}
+.Translate,.Theme{
+ img{
+ margin-inline: 6px;
+ }
+}
+.szh-menu{
+ background-color: var(--bg);
+}
+
+.modal-content{
+ background-color: var(--bg) !important;
+}
+.btn-primary{
+ background: var(--primary);
+ border-color: var(--primary) !important;
+ &:hover{
+ background: var(--primary);
+
+ }
+}
+.ModalHeader{
+ color: var(--text);
+}
+ .css-b62m3t-container .react-select__control{
+ background-color:var(--bg);
+ }
+
+ .react-select__control--is-disabled{
+ background-color:var(--bg) !important;
+ }
+
+
+
+
+
+
+ .ViewPage{
+ .card-header{
+ padding: 25px 25px 0 25px;
+ background: var(--bg) !important;
+ color: var(--text);
+ border-bottom: none !important;
+ display: flex; justify-content: space-between;
+ .card-title{
+ font-size: 2vw;
+ }
+ button{
+ background: var(--primary) ;
+ color: var(--bg);
+ font-weight: bold;
+ outline: none;
+ border: none;
+ min-width: 100px;
+ max-height: 40px;
+ }
+ }
+ .react-tabs__tab-list{
+ z-index: 1;
+ display: flex;
+ }
+ .react-tabs__tab{
+
+ flex: 1;
+ color: var(--text);
+
+ }
+ .react-tabs__tab--selected {
+ border-top: none; border-left: none; border-right: none;
+ border-bottom: 4px solid var(--primary);
+ color: var(--primary);
+ background: var(--bg2);
+
+ }
+
+ }
+
+
+ .react-tabs__tab:focus{
+ // background-color: red !important;
+
+ all: unset;
+ border-top: none; border-left: none; border-right: none;
+ border-bottom: 4px solid var(--primary);
+ color: var(--primary);
+ z-index: 99999;
+ background: var(--bg2);
+ min-width: 100px;
+
+ flex: 1;
+ color: var(--text);
+ max-height: 40px;
+
+ }
+
+
+ .ant-input-group-wrapper .ant-input-wrapper .ant-input-affix-wrapper{
+ background-color:var(--bg) !important;
+ color: var(--text) !important;
+}
+
+/* Input */
+.ant-input-wrapper .ant-input-affix-wrapper input[type=text]{
+ background-color:var(--bg) !important;
+ color: var(--text) !important;
+ &::placeholder{
+ color: var(--text) !important;
+ }
+}
+
+/* Warning */
+#root div .warning{
+ color:var(--secondary);
+}
+
+/* Content Division */
+#root .title-section p{
+ color:var(--secondary);
+}
+
+
+
+
+
+/* Iwjdpv */
+#root .card .sc-iwjdpV{
+ background-color:var(--bg2) !important;
+ color:var(--text) !important;
+}
+
+.Card{
+ padding: 30px;
+ @include Shadow;
+ background: var(--bg);
+ border-radius: 20px;
+}
+.SingleInfo{
+
+ svg{
+ color: green !important;
+ }
+}
+.ResposiveTabs{
+ padding-block: 20px;
+ min-height: 500px;
+}
+/* Ant tabs tab active */
+.ant-tabs-nav-wrap .ant-tabs-nav-list .ant-tabs-tab-active{
+ display:inline-block;
+ transform:translatex(0px) translatey(0px) !important;
+ }
+
+ /* Ant tabs content holder */
+ .VarianInfo .ant-tabs-left .ant-tabs-content-holder{
+ transform:translatex(0px) translatey(0px);
+
+ }
+ .ant-tabs-nav-wrap .ant-tabs-nav-list .ant-tabs-tab{
+align-self: center !important;
+padding: 10px 40px;
+
+ }
+
+ .VarianInfo{
+ padding: 10px 20px;
+ }
+
+
+ .react-tabs__tab-panel--selected .mt-4 .VarianInfo .ant-tabs-editable .ant-tabs-content-holder .ant-tabs-content .ant-tabs-tabpane .row .col .ant-upload-wrapper .ant-upload-select .ant-upload .ant-btn{
+ width:100% !important;
+ }
+ .tabstext{
+ margin-bottom: 10px;
+ }
+
+ .SellectTab{
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ }
+ .warning {
+ color: var(--primary) !important;
+ margin-bottom: 10px;
+ height: 4vw;
+ width: 4vw;
+ }
+ .css-1u0lry5-MuiChartsLegend-root {
+ direction: ltr;
+ }
+
+
+ ////// Tabs
+ .ant-tabs-nav-wrap .ant-tabs-nav-list .ant-tabs-tab{
+ display:flex;
+ color:var(--subtext) !important;
+ }
+
+ /* Ant tabs tab */
+ .ant-tabs-nav-list .ant-tabs-tab .ant-tabs-tab-btn{
+ color:var(--text) !important;
+ }
+
+ /* Ant tabs tab remove */
+ .ant-tabs-nav-list .ant-tabs-tab .ant-tabs-tab-remove{
+ color:var(--subtext) !important;
+ }
+ /* Ant tabs nav add */
+.ant-tabs-nav-wrap .ant-tabs-nav-list .ant-tabs-nav-add{
+ padding-top:5px;
+ padding-bottom:5px;
+ color:var(--primary) !important;
+
+ }
+
+ .ant-tabs-nav-wrap .ant-tabs-nav-list .ant-tabs-tab-active{
+
+.ant-tabs-tab-btn{
+ color:var(--text) !important;
+ font-weight: bold;
+ background: var(--bg);
+
+}
+.ant-tabs-tab-remove{
+ color:var(--text) !important;
+ }
+ }
+
+
+ .BarChart{
+ width: 100%;
+ height: 30vw
+ ;
+ }
+
+ @media (max-width: 800px) {
+ .BarChart{
+ width: 100%;
+ height: 50vw
+ ;
+ }
+ /* Text */
+.MuiChartsLegend-root .MuiChartsLegend-series text{
+ font-size:2vw !important;
+ }
+ .MuiChartsLegend-root .MuiChartsLegend-series .MuiChartsLegend-mark{
+ width:2vw;
+ height:2vw;
+ }
+ #root .DashboardLayout .DashboardLayout_Cover #DashboardLayout_Body .Layout_Children .row-cols-1 .BarChart .css-l0h214-MuiResponsiveChart-container .css-bd9tpx-MuiChartsSurface-root .MuiChartsLegend-root .MuiChartsLegend-series text{
+ transform: translatey(-2px) !important;
+ }
+
+
+ }
+ @media (max-width: 600px) {
+ .BarChart{
+ display:none;
+ }
+
+ .Page_Header{
+ flex-wrap: wrap;
+ }
+
+
+ }
+
+ /* Ant input affix wrapper */
+.ant-input-group-wrapper .ant-input-wrapper .ant-input-affix-wrapper{
+ height:40px;
+ }
+
+ /* Ant input search button */
+ .ant-input-wrapper .ant-input-group-addon .ant-input-search-button{
+ height:40px;
+ }
+
+
+
+
+
+
+
+ @media screen and (max-width: 600px) {
+ .SearchField,.SelectWSearchField{
+ display: none;
+ }
+}
+
+
+.AddNewTabText{
+ text-wrap: nowrap !important;
+ margin-left: 60px;
+ transform: translateY(-30px);
+}
+ @media screen and (max-width: 1000px) {
+
+.AddNewTabText{
+ transform: translateY(-50px);
+
+
+ }
+}
+.ar{
+ .AddNewTabText{
+ text-wrap: nowrap !important;
+ margin-right: 60px;
+ transform: translateY(-30px);
+ }
+ @media screen and (max-width: 1000px) {
+
+ .AddNewTabText{
+ transform: translateY(-50px);
+
+
+ }
+ }
+}
+/* Dynamic form complex */
+#dynamic_form_complex{
+ margin-bottom:5px;
+ }
+
+ /* Ant space gap col small */
+ #dynamic_form_complex .ant-space-gap-col-small{
+ margin-bottom:-9px !important;
+ transform:translatex(0px) translatey(0px);
+ }
+
+ /* Ant space item */
+ #dynamic_form_complex .ant-space-gap-col-small .ant-space-item{
+ margin-bottom:6px;
+ }
+
+ /* Span Tag */
+ #dynamic_form_complex .ant-space-item span{
+ transform: translatex(-13px) translatey(-12px);
+ }
+
+ #dynamic_form_complex .ant-space-gap-col-small {
+ width: 100%;
+ }
+ .Information{
+ margin-block: 20px;
+ }
+ .ant-form{
+ overflow-x: hidden;
+ }
+// .ant-tabs{
+// min-height: 200px;
+// }
+.gomecards{
+ min-height: 220px;
+}
+
+.ValidationFiledCusom{
+ display: flex;
+ flex-direction: column;
+ >*{
+ width: 100%;
+
+ }
+}
+
+
+// .withfillter{
+// display: flex;
+// flex-direction: column;
+// align-items: flex-end;
+// gap: 10px;
+// >div{
+// display: flex;
+// gap: 30px;
+// }
+// }
+.SelectWSearchField{
+ width: 200px;
+}
+.ant-drawer .ant-drawer-body{
+ padding: 0;
+}
+.RightSide{
+ flex-wrap: wrap;
+ justify-content: flex-end;
+}
+.orderStatus{
+ display: flex;
+ gap: 5px;
+ padding-inline: 10px;
+ text-wrap: nowrap;
+ white-space: nowrap;
+ width: 300px;
+ align-items: center;
+ justify-content: center;
+ svg{
+ color: var(--primary);
+ }
+
+}
+.orderStatus_select{
+ display: flex;
+ align-items: center;
+ gap: 5px;
+
+ svg{
+ color: var(--primary);
+ }
+
+}
+.CustomDateRange{
+ width: 240px;
+}
+.OrderDetails{
+ padding: 20px 4vw ;
+}
+.CustomNumber{
+ display: flex;
+ gap: 20px;
+}
+.SliderDataRange{
+ display: flex;
+ // flex-direction: column;
+ // justify-content: center;
+ // align-items: center;
+ // background: var(--bg);
+ // gap: 20px;
+ // width: 300px;
+ padding-inline: 20px;
+ h1{
+ font-size: 18px;
+ text-wrap: nowrap;
+ white-space: nowrap;
+ }
+
+}
+
+
+.ar{
+ .ant-tabs >.ant-tabs-nav{
+ direction: ltr !important;
+
+ }
+}
\ No newline at end of file
diff --git a/src/Styles/Layout/SideBar.scss b/src/Styles/Layout/SideBar.scss
new file mode 100644
index 0000000..15fd911
--- /dev/null
+++ b/src/Styles/Layout/SideBar.scss
@@ -0,0 +1,354 @@
+
+
+.SideBar {
+ display: flex;
+ flex-direction: column;
+ width: 260px;
+ height: 100%;
+ position: fixed;
+ background: var(--bg);
+ transition: .3s ease-in-out;
+@include Shadow;
+overflow-y: auto;
+overflow-x: hidden;
+&::-webkit-scrollbar {
+ width: 7px;
+ cursor: pointer;
+
+}
+
+&::-webkit-scrollbar-thumb {
+ background-color: transparent;
+ border-radius: 10px;
+ cursor: pointer;
+}
+&:hover{
+ &::-webkit-scrollbar {
+ width: 7px;
+}
+
+&::-webkit-scrollbar-thumb {
+ background-color: var(--primary);
+ border-radius: 10px;
+}
+}
+
+}
+
+.SideBar_Top {
+ @include Flex;
+ margin-block: 20px;
+ color: var(--primary);
+ z-index: 9999999;
+ img{
+ margin-inline: 10px;
+ width: 60px;
+ }
+ .HamburgerMenu{
+ z-index: 999999999999999;
+ height: 30px;
+ width: 30px;
+ svg{
+ font-size: 20px;
+ }
+ }
+}
+
+.SideBar_Links {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding-inline: 15px;
+
+}
+
+.SideBar_Link {
+
+ color: var(--text);
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ transition: .3s ease-in-out all;
+ margin-bottom: 5px;
+ width: 90%;
+ height: 45px;
+ border-radius: 10px;
+ margin-bottom: 10px;
+ font-weight: bold;
+ margin-left: 15px;
+ text-wrap: nowrap;
+
+
+ &:hover{
+ background: var(--primary);
+ color: var(--bg);
+ border-radius: 5px;
+ box-shadow: 2px 2px 7px 0 var(--shadow);
+ cursor: pointer;
+ transform: scale(1.01);
+ @include Shadow;
+
+ svg{
+
+ // background-color: var(--secondary);
+ color: var(--bg);
+
+ }
+ }
+ .DropDown_Svg svg{
+ color:var(--text);
+}
+
+
+
+ svg {
+ padding: 5px;
+ border-radius: 10px;
+ // background-color: var(--bg2);
+ color: var(--secondary);
+ margin-left: 10px;
+
+ font-size: 30px;
+
+ &:hover{
+ background-color: var(--primary);
+ color: var(--bg);
+ }
+ }
+
+
+}
+.ar{
+ .SideBar_Link{
+ margin-right: 15px !important;
+ margin-left: 0px !important;
+ svg {
+
+ margin-right: 10px;
+ margin-left: 0px !important;
+
+
+ }
+
+
+ }
+}
+
+.SideBar_Links_Header{
+
+ margin-block: 10px;
+ font-size: 12px;
+ background: var(--bg2);
+ height: 50px;
+ @include Flex;
+
+ width: 100%;
+}
+.Active_SideBar_Link{
+ background: var(--linear);
+ color: var(--bg);
+ border-radius: 5px;
+ box-shadow: 2px 2px 7px 0 var(--shadow);
+
+ svg {
+ background-color: transparent;
+ color: var(--bg);
+
+ }
+}
+.glass{
+ .Active_SideBar_Link{
+ background: var(--linear);
+ color: var(--bg);
+ border-radius: 5px;
+ box-shadow: 2px 2px 7px 0 transparent;
+ background-color: rgba(16 18 27 / 1%);
+ backdrop-filter: blur(24px);
+ }
+ .SideBar_Link {
+ &:hover {
+ background-color: rgba(16 18 27 / 40%);
+ backdrop-filter: blur(24px);
+ }
+ &:hover{
+ background: transparent;
+ color: var(--bg);
+ border-radius: 5px;
+ box-shadow: 1px 2px 7px 0 transparent;
+ cursor: pointer;
+ transform: scale(1.01);
+ svg{
+
+ background-color:transparent;
+ color: var(--text);
+
+ }
+ }
+ }
+}
+
+
+.DropDown_Text{
+ width: 100px;
+// text-overflow: ellipsis;
+// overflow: hidden;
+ margin-right: 30px;
+}
+
+
+.SideBar_Open{
+ width: 90px;
+ .Active_SideBar_Link,.SideBar_Link:hover{
+ width: 60%;
+ }
+ .Link_Text,.DropDown_Text,.DropDown_Svg{
+ display: none;
+ }
+
+ .HamburgerMenu{
+ display: none;
+ }
+ .SideBar_Top{
+ cursor: pointer;
+ }
+ }
+ .DropDown_SideBar_Link{
+ background: var(--bg2);
+ }
+
+
+
+ .KarimLogo{
+ width: 50px;
+ margin-inline: 70px;
+
+ .cls-1, .cls-2 {
+ fill:var(--primary) !important;
+ }
+ }
+
+
+
+
+
+ .SideBar_Open{
+.Etaxi{
+ width: 60px;
+ height: 30px;
+ margin-inline: 40px;
+ }
+ }
+ .noOpen{
+.Etaxi{
+ width: 90px;
+ height:30px;
+ margin-inline: 40px;
+ }
+ }
+
+@media screen and (max-width: 700px) {
+ .out_Sidebar{
+.SideBar_Open,.noOpen{
+ display: none;
+ // transform: translateX(-100px);
+}
+ }
+
+.DashboardLayout_Body_Open,.DashboardLayout .DashboardLayout_Body{
+ left: 30px !important;
+ width : calc(100% - 60px) !important;
+}
+.ar{
+ .DashboardLayout_Body{
+ right: 30px !important;
+
+ }
+ .DashboardLayout_Body_Open{
+ right: 30px !important;
+ width: calc(96% - 140px);
+ transition: 1s ease-in-out;
+
+
+ }
+}
+
+}
+
+
+
+
+.ant-drawer-left .ant-drawer-wrapper-body .ant-drawer-header{
+ display:none;
+}
+
+/* Ant drawer body */
+.ant-drawer-left .ant-drawer-wrapper-body .ant-drawer-body{
+ padding-left:0px;
+ padding-right:0px;
+ padding-top:0px;
+ padding-bottom:0px;
+ background: var(--bg);
+}
+
+
+.ant-drawer-left{
+
+ .SideBar_Top{
+ display: none;
+ }
+ .ant-drawer-body div .RoutesLinks{
+ margin-top:27px;
+}
+}
+
+
+.ant-drawer-left .ant-drawer-content{
+
+ @include GlassModeCover;
+ // @include GlassModeBG;
+ color: var(--primary);
+ overflow-x: hidden;
+
+
+}
+
+
+
+
+
+
+.ant-drawer-right .ant-drawer-wrapper-body .ant-drawer-header{
+ display:none;
+}
+
+/* Ant drawer body */
+.ant-drawer-right .ant-drawer-wrapper-body .ant-drawer-body{
+ padding-left:0px;
+ padding-right:0px;
+ padding-top:0px;
+ padding-bottom:0px;
+ background: var(--bg);
+}
+
+
+.ant-drawer-right{
+
+ .SideBar_Top{
+ display: none;
+ }
+ .ant-drawer-body div .RoutesLinks{
+ margin-top:27px;
+}
+}
+
+
+.ant-drawer-right .ant-drawer-content{
+
+ @include GlassModeCover;
+ // @include GlassModeBG;
+ color: var(--primary);
+ overflow-x: hidden;
+
+
+}
diff --git a/src/Styles/Layout/Table.scss b/src/Styles/Layout/Table.scss
new file mode 100644
index 0000000..5bff747
--- /dev/null
+++ b/src/Styles/Layout/Table.scss
@@ -0,0 +1,101 @@
+ .sc-hKwDye,.card-body div nav{
+ background-color:var(--bg) !important;
+ color: var(--text) !important;
+ }
+ .glass{
+ /* Hmcd */
+ .sc-dkPtRN .sc-hKwDye .sc-crHmcD{
+ background-color:transparent;
+ }
+
+ /* Ptrn */
+ .sc-bdvvtL .sc-gsDKAQ .sc-dkPtRN{
+ background-color:transparent;
+ }
+
+ /* Card */
+ #root .card{
+ transform:translatex(0px) translatey(0px);
+ }
+
+ /* Bdvvtl */
+ .sc-dlVxhl .sc-fKVqWL .sc-bdvvtL{
+ background-color:transparent;
+ }
+
+
+ /* Row 12 */
+ .rdt_TableRow{
+ background-color:transparent !important;
+ }
+ //// table
+ .sc-fKVqWL .sc-bdvvtL .sc-iwjdpV{
+ background-color:transparent;
+ color:var(--text);
+}
+
+
+ }
+
+
+ :where(.css-dev-only-do-not-override-1adbn6x).ant-pagination .ant-pagination-total-text,
+ a:not([href]):not([class]), a:not([href]):not([class]):hover,
+ .dLwgoF svg
+ {
+ color: var(--text);
+ }
+ :where(.css-dev-only-do-not-override-1adbn6x).ant-pagination .ant-pagination-item-active a{
+ color: var(--primary) !important;
+ }
+
+
+ .modal .modal-dialog .modal-content{
+ z-index: 999999999 !important;
+ }
+
+
+ .ImageWname{
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+
+ }
+
+/* Ant form item control */
+#dynamic_form_complex div .ant-form-item-control{
+ transform:translatex(0px) translatey(0px);
+ min-width:93%;
+ }
+
+ /* Ant form item row */
+ #dynamic_form_complex div .ant-form-item-row{
+ transform:translatex(0px) translatey(0px);
+ overflow:hidden;
+ }
+
+ /* Ant space item */
+ #dynamic_form_complex div .ant-space-item{
+ min-width:47%;
+ }
+
+
+
+
+ .ant-tabs-nav-wrap .ant-tabs-nav-list .ant-tabs-tab{
+ direction: ltr;
+ }
+
+
+ .ar{
+ .VarianInfo .ant-tabs-editable .ant-tabs-nav{
+ margin-left:12px;
+ }
+ }
+
+
+ .react-tabs .react-tabs__tab-panel--selected .mt-4 .d-flex .ant-tabs-left{
+ width:100% !important;
+ }
+ :where(.css-dev-only-do-not-override-6j9yrn).ant-tabs {
+ width:100% !important;
+ }
\ No newline at end of file
diff --git a/src/Styles/component/DarkStyle.scss b/src/Styles/component/DarkStyle.scss
new file mode 100644
index 0000000..07e412e
--- /dev/null
+++ b/src/Styles/component/DarkStyle.scss
@@ -0,0 +1,115 @@
+
+.dark{
+ .modal_info{
+ color: #fff !important;
+}
+.modal-title{
+ color: #fff !important;
+}
+
+// pagination
+ .ant-pagination-item-container .ant-pagination-item-ellipsis{
+ color: #fff !important;
+ }
+ .ant-pagination{
+ color: #fff;
+ }
+ .anticon{
+ color: #fff;
+ }
+ .ant-pagination-item-active{
+ background: #ffffffd6;
+ border: 1px solid var(--primary);
+ a{
+ color: black !important;
+ }
+ }
+// Add Account Page
+ .add_account_title{
+ color: #fff;
+ }
+// INformation pages
+ .Information_title{
+ color: #fff;
+ }
+//karim field image
+ .ant-upload-list .ant-upload-list-item .ant-upload-list-item-name{
+ color: #fff !important;
+ }
+ .anticon svg{
+ color: #fff !important;
+ }
+//LyTable Arrow
+ .gPLhoV{
+ svg{
+ display: none;
+ }
+ }
+// single order
+ .Single_order_title, .Single_order_body{
+ color: #fff !important;
+ }
+// change password
+ .change_password_body{
+ color: #fff !important;
+ }
+ .dark_mode_white_color{
+ color: #fff !important;
+ }
+}
+
+
+
+
+
+
+
+
+//galss
+.glass{
+ //LyTable Arrow
+ .gPLhoV{
+ svg{
+ display: none;
+ }
+ }
+ // add account
+ .add_account_title{
+ color: #fff;
+ }
+ //information
+ .Information_title{
+ color: #fff;
+ }
+ //paginate
+ .ant-pagination{
+ color: #fff;
+ }
+ .anticon{
+ color: #fff;
+ }
+ .ant-pagination-item-active{
+ background: #ffffffd6;
+ border: 1px solid var(--primary);
+ a{
+ color: black !important;
+ }
+ }
+ //error page
+ .error_show{
+ margin-top: 3vw !important;
+ }
+//chart
+ .apexcharts-canvas {
+ // color: #edf4f4 !important;
+ background: #ffffff;
+ }
+// single order
+ .Single_order_title, .Single_order_body{
+ color: #fff !important;
+ }
+// change password
+ .change_password_body,.change_password_header{
+ color: #fff !important;
+ }
+}
\ No newline at end of file
diff --git a/src/Styles/component/DriverInfoSocket.scss b/src/Styles/component/DriverInfoSocket.scss
new file mode 100644
index 0000000..94b2e14
--- /dev/null
+++ b/src/Styles/component/DriverInfoSocket.scss
@@ -0,0 +1,102 @@
+.driverInfo_socket_container{
+ background: #fff;
+ width: 100%;
+ height: 100vh;
+ .image_container{
+ display: flex;justify-content: center;
+ .driver_track_image{
+ border: 4px solid var(--secondary);
+ display: flex;justify-content: center;align-items: center;
+ border-radius: 50% !important;
+ margin: auto;
+ margin-top: 6px;
+ width: 70px;
+ height: 70px;
+ object-fit: contain;
+ }
+ }
+
+ .info_container{
+ border: 3px solid var(--secondary);
+ width: 90%;
+ border-radius: 30px;
+ background: #fff;
+ margin-top: .7vw;
+ padding: 10px 10px;
+ display: flex; flex-direction: column;
+ margin-inline:auto ;
+ h4{
+ text-align: center;
+ }
+ .icon_info{
+ color: var(--primary);
+ width: 10%;
+ }
+ .main_info_cont{
+ display: flex;justify-content: center;align-items: center;
+ border-bottom: 1px solid var(--secondary);
+ .driver_info{
+ width: 90%;
+ margin-inline: auto;
+ text-transform: capitalize;
+ color: #000;
+ font-size: 14px;
+ font-weight: 600;
+ display: flex; justify-content: space-between;align-items: center;
+ margin-bottom: .5vw;
+ .driver_respons{
+ padding-top: 5px;
+ margin-left: 1vw;
+ font-size: 11px;
+ font-weight: 400;
+ color: var(--primary);
+ }
+ }
+ }
+
+ }
+ .phone_container{
+ border: 3px solid var(--secondary);
+ display: flex;align-items: center;justify-content: center;
+ background: #fff;
+ padding: 20px 10px;
+ width: 90%;height: 25px;
+ border-radius: 30px;
+ margin-inline:auto;
+ margin-top: 1vw;
+ svg{
+ font-size: 28px;
+ margin: 0 40px 0 10px;
+ }
+ .driver_respons{
+ font-size: 28px;
+ }
+ }
+}
+
+@media screen and (max-width: 360px) {
+ .phone_container{
+ svg{
+ font-size: 17px !important;
+ margin-left: 10px !important;
+ }
+ .driver_respons{
+ font-size: 17px !important;
+ }
+ }
+}
+
+.dark{
+ .driverInfo_socket_container{
+ background: var(--bg) !important;
+ .info_container{
+ background: #000 !important;
+ .driver_info{
+ color: #fff !important;
+ }
+ }
+ .phone_container{
+ background: #000 !important;
+ }
+ }
+}
diff --git a/src/Styles/component/ErrorPage.scss b/src/Styles/component/ErrorPage.scss
new file mode 100644
index 0000000..75da78c
--- /dev/null
+++ b/src/Styles/component/ErrorPage.scss
@@ -0,0 +1,21 @@
+.error_show{
+ display: flex;justify-content: center;align-items: center; flex-direction: column;
+ // background: #000;
+ height: 40vh;
+ .error_icon{
+ text-align: center;
+ color: var(--secondary);
+ font-size: 7vw;
+ }
+ .error_text{
+ text-align: center;
+ color: var(--primary);
+ font-size: 4vw;
+ }
+}
+
+.socket_debug_error{
+ font-size: 30px ;
+ font-weight: 600;
+ color: var(--secondary);
+}
\ No newline at end of file
diff --git a/src/Styles/component/Tab_Info.scss b/src/Styles/component/Tab_Info.scss
new file mode 100644
index 0000000..7b2b1b2
--- /dev/null
+++ b/src/Styles/component/Tab_Info.scss
@@ -0,0 +1,14 @@
+
+.Tab_Info_Container{
+ display: flex;justify-content: start;align-items: center;
+ .Tab_Info{
+ font-size: 1.4vw;
+ padding-left: .5vw;
+ margin-bottom: 0;
+ }
+ .SignleDriverInfoIcon{
+ svg{
+ width: 90%;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Styles/component/printButton.scss b/src/Styles/component/printButton.scss
new file mode 100644
index 0000000..3f8c242
--- /dev/null
+++ b/src/Styles/component/printButton.scss
@@ -0,0 +1,16 @@
+.print_button{
+ border: 2px solid var(--primary);
+ background-color: var(--primary);
+ border-radius: 0.5vw;
+ padding:.61vw 1.6vw;
+ font-size: 1vw;
+ display: flex; justify-content: center; align-items: center;
+ box-shadow: 2px 2px 7px 0 var(--primary);
+ margin-right: -770px !important;
+ text-transform: capitalize;
+ font-weight: 700;
+ &:hover{
+ background-color:var(--primary);
+ border: 2px solid var(--primary);
+ }
+}
\ No newline at end of file
diff --git a/src/Styles/component/radio.scss b/src/Styles/component/radio.scss
new file mode 100644
index 0000000..b5b90cb
--- /dev/null
+++ b/src/Styles/component/radio.scss
@@ -0,0 +1,79 @@
+.ant-radio-button-wrapper{
+ span{
+ position: absolute !important;
+ top: -6px;
+ left: 6px;
+ font-size: 8.5px !important;
+ color: #000 !important;
+ }
+}
+
+
+
+.ant-radio-button-wrapper {
+ // margin-left: 10px;
+ width: 50px !important;
+ height: 20px !important;
+}
+
+
+:where(.css-dev-only-do-not-override-6j9yrn).ant-radio-button-wrapper:first-child{
+ border-radius: 5px 0px 0px 0px !important;
+ margin-left: 10px;
+}
+
+:where(.css-dev-only-do-not-override-6j9yrn).ant-radio-button-wrapper:nth-child(2){
+ border-radius: 0px 5px 0px 0px !important;
+}
+
+:where(.css-dev-only-do-not-override-6j9yrn).ant-radio-button-wrapper:last-child{
+ border-radius: 0px 0px 5px 5px !important;
+ width: 100px !important;
+ border: 1px solid #d9d9d9;
+ margin-left: 10px;
+ span{
+ font-size: 10.5px !important;
+ left: 30px !important;
+ }
+}
+
+:where(.css-dev-only-do-not-override-6j9yrn).ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):first-child{
+ background: #04ff00 !important;
+ border: 1px solid #000;
+ span{
+ color: #fff !important;
+ }
+}
+
+:where(.css-dev-only-do-not-override-6j9yrn).ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):nth-child(2){
+ background: #bcbcbc !important;
+ border: 1px solid #000;
+ span{
+ color: #fff !important;
+ }
+}
+
+:where(.css-dev-only-do-not-override-6j9yrn).ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):last-child{
+ background: #e20000 !important;
+ border: 1px solid #000 ;
+ span{
+ color: #fff !important;
+ }
+}
+
+
+:where(.css-dev-only-do-not-override-6j9yrn).ant-radio-button-wrapper:not(:first-child)::before {
+ display: none !important;
+}
+
+
+
+.ar{
+ :where(.css-dev-only-do-not-override-6j9yrn).ant-radio-button-wrapper:first-child{
+ border-radius: 0px 5px 0px 0px !important;
+ margin-left: 0px;
+ }
+ :where(.css-dev-only-do-not-override-6j9yrn).ant-radio-button-wrapper:nth-child(2){
+ border-radius: 5px 0px 0px 0px !important;
+ }
+}
\ No newline at end of file
diff --git a/src/api/Categories.ts b/src/api/Categories.ts
new file mode 100644
index 0000000..40cc176
--- /dev/null
+++ b/src/api/Categories.ts
@@ -0,0 +1,24 @@
+
+import useGetQueryPagination from "./helper/ueGetPagination";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetOneQuery from "./helper/useGetOneQuery";
+import useUpdateMutationPost from "./helper/useUpdateMutationPut";
+
+const API = {
+ ADD: `category`,
+ GET_ALL: `category`,
+ DELETE: `category`,
+ UPDATE: `category`,
+
+};
+const KEY = "categories"
+
+
+export const useGetCategories = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params);
+export const useGetOneCategories = () => useGetOneQuery(KEY, API.GET_ALL);
+
+export const useAddCategories = () => useAddMutation(KEY, API.ADD);
+export const useUpdateCategories = (method?:any) => useUpdateMutationPost(KEY, API.UPDATE,true,method);
+
+export const useDeleteCategories = () =>useDeleteMutation(KEY, API.DELETE);
diff --git a/src/api/GuestApi.ts b/src/api/GuestApi.ts
new file mode 100644
index 0000000..2be058e
--- /dev/null
+++ b/src/api/GuestApi.ts
@@ -0,0 +1,25 @@
+
+import useGetQuery from "./helper/useGetQuery";
+import useGetQueryPagination from "./helper/ueGetPagination";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetOneQuery from "./helper/useGetOneQuery";
+import useUpdateMutationPost from "./helper/useUpdateMutationPut";
+
+const API = {
+ ADD: `guest/restaurant`,
+ GET_ALL: `guest/restaurant`,
+ DELETE: `guest/restaurant`,
+ UPDATE: `guest/restaurant`,
+
+};
+const KEY = "setting"
+
+
+export const useGetSetting = (params?:any) => useGetQuery(KEY, API.GET_ALL,params);
+export const useGetOneSetting = () => useGetOneQuery(KEY, API.GET_ALL);
+
+export const useAddSetting = () => useAddMutation(KEY, API.ADD);
+export const useUpdateSetting = (method?:any) => useUpdateMutationPost(KEY, API.UPDATE,true,method);
+
+export const useDeleteSetting = () =>useDeleteMutation(KEY, API.DELETE);
diff --git a/src/api/Meal.ts b/src/api/Meal.ts
new file mode 100644
index 0000000..b348d10
--- /dev/null
+++ b/src/api/Meal.ts
@@ -0,0 +1,24 @@
+
+import useGetQueryPagination from "./helper/ueGetPagination";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetOneQuery from "./helper/useGetOneQuery";
+import useUpdateMutationPost from "./helper/useUpdateMutationPut";
+
+const API = {
+ ADD: `meal`,
+ GET_ALL: `meal`,
+ DELETE: `meal`,
+ UPDATE: `meal`,
+
+};
+const KEY = "Meal"
+
+
+export const useGetMeal = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params);
+export const useGetOneMeal = () => useGetOneQuery(KEY, API.GET_ALL);
+
+export const useAddMeal = () => useAddMutation(KEY, API.ADD);
+export const useUpdateMeal = (method?:any) => useUpdateMutationPost(KEY, API.UPDATE,true,method);
+
+export const useDeleteMeal = () =>useDeleteMutation(KEY, API.DELETE);
diff --git a/src/api/Offer.ts b/src/api/Offer.ts
new file mode 100644
index 0000000..8963e16
--- /dev/null
+++ b/src/api/Offer.ts
@@ -0,0 +1,24 @@
+
+import useGetQueryPagination from "./helper/ueGetPagination";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetOneQuery from "./helper/useGetOneQuery";
+import useUpdateMutationPost from "./helper/useUpdateMutationPut";
+
+const API = {
+ ADD: `offer`,
+ GET_ALL: `offer`,
+ DELETE: `offer`,
+ UPDATE: `offer`,
+
+};
+const KEY = "Offer"
+
+
+export const useGetOffer = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params);
+export const useGetOneOffer = () => useGetOneQuery(KEY, API.GET_ALL);
+
+export const useAddOffer = () => useAddMutation(KEY, API.ADD);
+export const useUpdateOffer = (method?:any) => useUpdateMutationPost(KEY, API.UPDATE,true,method);
+
+export const useDeleteOffer = () =>useDeleteMutation(KEY, API.DELETE);
diff --git a/src/api/Restaurant.ts b/src/api/Restaurant.ts
new file mode 100644
index 0000000..78a191f
--- /dev/null
+++ b/src/api/Restaurant.ts
@@ -0,0 +1,24 @@
+
+import useGetQueryPagination from "./helper/ueGetPagination";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetOneQuery from "./helper/useGetOneQuery";
+import useUpdateMutationPost from "./helper/useUpdateMutationPut";
+
+const API = {
+ ADD: `restaurant`,
+ GET_ALL: `restaurant`,
+ DELETE: `restaurant`,
+ UPDATE: `restaurant`,
+
+};
+const KEY = "Restaurant"
+
+
+export const useGetRestaurant = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params);
+export const useGetOneRestaurant = () => useGetOneQuery(KEY, API.GET_ALL);
+
+export const useAddRestaurant = () => useAddMutation(KEY, API.ADD);
+export const useUpdateRestaurant = (method?:any) => useUpdateMutationPost(KEY, API.UPDATE,true,method);
+
+export const useDeleteRestaurant = () =>useDeleteMutation(KEY, API.DELETE);
diff --git a/src/api/auth.ts b/src/api/auth.ts
new file mode 100644
index 0000000..f9df5ba
--- /dev/null
+++ b/src/api/auth.ts
@@ -0,0 +1,10 @@
+import useAddMutation from "./helper/useAddMutation";
+
+
+
+
+const KEY = "AUTH"
+const API = {
+ LOGIN: `login`,
+ };
+export const useLoginAdmin = ()=>useAddMutation(KEY , API.LOGIN,"login_successful")
\ No newline at end of file
diff --git a/src/api/config.ts b/src/api/config.ts
new file mode 100644
index 0000000..d6ee3de
--- /dev/null
+++ b/src/api/config.ts
@@ -0,0 +1,17 @@
+
+// export const BaseURL = `https://etaxiapi.rayantaxi.com/`;
+// export const BaseURL = `https://etaxi.Point.net/`;
+export const BaseURL = `https://e-menus-back-dev.point-dev.net/api/`;
+export const ImageBaseURL = `https://e-menus-back-dev.point-dev.net`;
+
+
+// export const BaseURL = `http://192.168.1.14:8000/`;
+export const BaseURL_IMAGE = BaseURL.slice(0,-1);
+
+
+const PROJECT_NAME = "E-Menu"
+
+export const TOKEN_KEY = PROJECT_NAME + "_TOKEN"
+
+export const USER_KEY = PROJECT_NAME + "_USER"
+
diff --git a/src/api/helper/AxiosBuilder.ts b/src/api/helper/AxiosBuilder.ts
new file mode 100644
index 0000000..3f19067
--- /dev/null
+++ b/src/api/helper/AxiosBuilder.ts
@@ -0,0 +1,49 @@
+import axios, { AxiosInstance, AxiosRequestConfig ,ResponseType } from 'axios';
+
+
+class AxiosBuilder {
+ private baseURL: string = '';
+ private headers: Record = {};
+ private timeout: number = 60000; // Request failed with 60 second
+ private withCreds: boolean = false;
+ private responseType: ResponseType = 'json';
+ // Custom Another Props with Your Position
+
+
+ withBaseURL(baseURL: string): AxiosBuilder {
+ this.baseURL = baseURL;
+ return this;
+ }
+
+ withHeaders(headers: Record): AxiosBuilder {
+ this.headers = headers;
+ return this;
+ }
+
+ withTimeout(timeout: number): AxiosBuilder {
+ this.timeout = timeout;
+ return this;
+ }
+
+
+ withResponseType(responseType: ResponseType): AxiosBuilder {
+ this.responseType = responseType;
+ return this;
+ }
+
+
+ build(): AxiosInstance {
+ const config: AxiosRequestConfig = {
+ baseURL: this.baseURL,
+ headers: this.headers,
+ timeout: this.timeout,
+ responseType:this.responseType
+ };
+
+ return axios.create(config);
+ }
+ }
+
+
+export default AxiosBuilder
+
diff --git a/src/api/helper/buildFormData.ts b/src/api/helper/buildFormData.ts
new file mode 100644
index 0000000..eb1f736
--- /dev/null
+++ b/src/api/helper/buildFormData.ts
@@ -0,0 +1,27 @@
+
+
+export const buildFormData = (
+ formData: FormData,
+ data: any,
+ parentKey?: string
+ ): void => {
+ if (
+ data &&
+ typeof data === "object" &&
+ !(data instanceof Date) &&
+ !(data instanceof File)
+ ) {
+ Object.keys(data).forEach((key) => {
+ buildFormData(
+ formData,
+ data[key],
+ parentKey ? `${parentKey}[${key}]` : key
+ );
+ });
+ } else {
+ const value = data == null ? "" : data;
+
+ formData.append(parentKey as string, value);
+ }
+ };
+
\ No newline at end of file
diff --git a/src/api/helper/ueGetPagination.tsx b/src/api/helper/ueGetPagination.tsx
new file mode 100644
index 0000000..f570e1c
--- /dev/null
+++ b/src/api/helper/ueGetPagination.tsx
@@ -0,0 +1,44 @@
+import { useQuery } from 'react-query';
+import useAxios from './useAxios';
+import { useLocation, useNavigate } from 'react-router-dom';
+import useAuthState from '../../lib/state mangment/AuthState';
+
+export default function useGetQueryPagination(KEY: string | string[], Api: string, params: any = {}, options: any = {}, dontSearchBy?: string) {
+ const axios = useAxios();
+ const location = useLocation();
+ let pagination = location?.search || '';
+ const language = localStorage.getItem("language") ?? "en"
+
+ const { logout } = useAuthState();
+ const navigate = useNavigate();
+
+ if (dontSearchBy && pagination.includes(dontSearchBy)) {
+ const searchParams = new URLSearchParams(pagination);
+ searchParams.delete(dontSearchBy);
+ pagination = searchParams.toString();
+ }
+ if (pagination && !pagination.startsWith('?')) {
+ pagination = '?' + pagination;
+ }
+
+ // Check if pagination exists and append it to the API endpoint
+ const paginationParams = pagination ? pagination + '&orderById=desc' : '?orderById=desc';
+ const apiUrl = Api + paginationParams;
+
+ return useQuery(
+ [Array.isArray(KEY) ? KEY.join(',') : KEY, pagination,language], async () => {
+ const response = await axios.get(apiUrl, { params });
+ return response.data;
+ },
+ {
+ onError: (error: any) => {
+ if (error?.response?.status === 401 || error?.response?.status === 403) {
+ logout();
+ navigate("/auth");
+ }
+ },
+ refetchOnWindowFocus: false,
+ ...options
+ }
+ );
+}
diff --git a/src/api/helper/useAddMutation.ts b/src/api/helper/useAddMutation.ts
new file mode 100644
index 0000000..88ffb5d
--- /dev/null
+++ b/src/api/helper/useAddMutation.ts
@@ -0,0 +1,39 @@
+import { useMutation, useQueryClient, UseMutationResult } from 'react-query';
+import { toast } from 'react-toastify';
+import useAxios from './useAxios';
+import { useTranslation } from 'react-i18next';
+
+type AxiosResponse = {
+ message: string;
+ data:any ,
+ success:true
+};
+
+function useAddMutation(key: string, url: string,message?:string): UseMutationResult {
+ const axios = useAxios();
+ const [t] = useTranslation();
+ const queryClient = useQueryClient();
+
+ return useMutation(
+ async (dataToSend) => {
+ const { data } = await axios.post(url, dataToSend,{
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ } );
+ return data;
+ },
+ {
+ onSuccess: (data) => {
+ queryClient.invalidateQueries([key]);
+ toast.success(data.message || t(message??"") || t("added_successful"));
+ },
+ onError: (error:any) => {
+ const message = error?.response?.data?.message || t("failed_to_add_data");
+ toast.error(message);
+ }
+ }
+ );
+}
+
+export default useAddMutation;
diff --git a/src/api/helper/useAddMutationJson.ts b/src/api/helper/useAddMutationJson.ts
new file mode 100644
index 0000000..8e9864b
--- /dev/null
+++ b/src/api/helper/useAddMutationJson.ts
@@ -0,0 +1,35 @@
+import { useMutation, useQueryClient, UseMutationResult } from 'react-query';
+import { toast } from 'react-toastify';
+import useAxios from './useAxios';
+import { useTranslation } from 'react-i18next';
+
+type AxiosResponse = {
+ message: string;
+ data:any ,
+ success:true
+};
+
+function useAddMutationJson(key: string, url: string): UseMutationResult {
+ const axios = useAxios();
+ const [t] = useTranslation();
+ const queryClient = useQueryClient();
+
+ return useMutation(
+ async (dataToSend) => {
+ const { data } = await axios.post(url, dataToSend);
+ return data;
+ },
+ {
+ onSuccess: (data) => {
+ queryClient.invalidateQueries([key]);
+ toast.success(data.message || t("added_successful"));
+ },
+ onError: (error:any) => {
+ const message = error?.response?.data?.message || t("failed_to_add_data");
+ toast.error(message);
+ }
+ }
+ );
+}
+
+export default useAddMutationJson;
diff --git a/src/api/helper/useAxios.ts b/src/api/helper/useAxios.ts
new file mode 100644
index 0000000..7cdd7db
--- /dev/null
+++ b/src/api/helper/useAxios.ts
@@ -0,0 +1,25 @@
+import { BaseURL } from '../config'
+import useAuthState from '../../lib/state mangment/AuthState'
+import AxiosBuilder from './AxiosBuilder'
+
+function useAxios() {
+ const {isAuthenticated , token}= useAuthState()
+
+ const buildAxios = new AxiosBuilder().
+ withBaseURL(BaseURL)
+ .withResponseType('json')
+ .withTimeout(120000)
+ .withHeaders({"Content-Type" :"application/json"})
+
+
+ if(isAuthenticated){
+
+ buildAxios.withHeaders({ Authorization: 'Bearer '+ token })
+ }
+
+ return (
+ buildAxios.build()
+ )
+}
+
+export default useAxios
\ No newline at end of file
diff --git a/src/api/helper/useDeleteMutation.ts b/src/api/helper/useDeleteMutation.ts
new file mode 100644
index 0000000..87e84ca
--- /dev/null
+++ b/src/api/helper/useDeleteMutation.ts
@@ -0,0 +1,35 @@
+import { useMutation, useQueryClient, UseMutationResult } from 'react-query';
+import { toast } from 'react-toastify';
+import useAxios from './useAxios';
+import { useTranslation } from 'react-i18next';
+
+type AxiosResponse = {
+ message: string;
+ // Add other properties as needed
+};
+
+function useDeleteMutation(key:any , url: string): UseMutationResult {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const {t} = useTranslation();
+
+ return useMutation(
+ async ({dataToSend,id}:any) => {
+ const { data } = await axios.delete(url+"/"+id );
+ return {...data, id,dataToSend};
+ },
+ {
+ onSuccess: (data) => {
+ queryClient.invalidateQueries(key);
+ toast.success(t('deleted_successfully'));
+ },
+ onError: (error:any) => {
+ const message = error?.response?.data?.message || t("failed_to_add_data");
+ toast.error(message);
+ }
+ },
+
+ );
+}
+
+export default useDeleteMutation;
diff --git a/src/api/helper/useGetOneQuery.ts b/src/api/helper/useGetOneQuery.ts
new file mode 100644
index 0000000..c0719f6
--- /dev/null
+++ b/src/api/helper/useGetOneQuery.ts
@@ -0,0 +1,39 @@
+import { useQuery } from 'react-query';
+import useAxios from './useAxios';
+import useAuthState from '../../lib/state mangment/AuthState';
+import { useNavigate, useParams } from 'react-router-dom';
+
+function useGetOneQuery(key: string, url: string , params:any={},options:any={}) {
+ const axios = useAxios();
+ const {logout} = useAuthState()
+ const language = localStorage.getItem("language") ?? "en"
+ const navigate = useNavigate()
+ const {id} = useParams()
+
+ return useQuery(
+ [id, key,language],
+ async () => {
+ const response = await axios.get(url+"/"+ id+`?lang=${language}`);
+ return response.data;
+ },
+
+
+ {
+ onError: (error:any) => {
+ if(error.response.status == 401 || error.response.status == 403){
+ logout()
+ navigate("/auth")
+
+ }
+
+ },
+ cacheTime: 0, // Set cacheTime to 0 to disable caching
+ refetchOnWindowFocus: false,
+
+ ...options
+
+ }
+ );
+}
+
+export default useGetOneQuery;
diff --git a/src/api/helper/useGetQuery.ts b/src/api/helper/useGetQuery.ts
new file mode 100644
index 0000000..aedcce8
--- /dev/null
+++ b/src/api/helper/useGetQuery.ts
@@ -0,0 +1,24 @@
+import { useQuery } from 'react-query';
+import useAxios from './useAxios';
+
+function useGetQuery(KEY: string | string[], url: string, params: any = {}, options: any = {}) {
+ const axios = useAxios();
+ const show = params.show ? "/" + params.show : '';
+
+ const filteredParams = Object.fromEntries(
+ Object.entries(params).filter(([_, value]) => value !== '')
+ );
+
+ return useQuery([KEY, filteredParams], async () => {
+ const response = await axios.get(url + show, { params: filteredParams });
+ return response.data;
+ }, {
+ onError: (error) => {
+ console.error('An error occurred:', error);
+ },
+ refetchOnWindowFocus: false,
+ ...options
+ });
+}
+
+export default useGetQuery;
diff --git a/src/api/helper/useGetSingleQuery.ts b/src/api/helper/useGetSingleQuery.ts
new file mode 100644
index 0000000..e930dc7
--- /dev/null
+++ b/src/api/helper/useGetSingleQuery.ts
@@ -0,0 +1,38 @@
+import { useQuery } from 'react-query';
+import useAxios from './useAxios';
+import useAuthState from '../../lib/state mangment/AuthState';
+import { useNavigate, useParams } from 'react-router-dom';
+
+function useGetSingleQuery(key: string, url: string , params:any={},options:any={}) {
+ const axios = useAxios();
+ const {logout} = useAuthState()
+ const language = localStorage.getItem("language") ?? "en"
+ const navigate = useNavigate()
+ const {id} = useParams()
+
+ return useQuery(
+ [id, key,params?.id],
+ async () => {
+ const response = await axios.get(url+"?"+params?.name+"="+params?.id+`?lang=${language}`);
+ return response.data;
+ },
+
+
+ {
+ onError: (error:any) => {
+ if(error.response.status == 401 || error.response.status == 403){
+ logout()
+ navigate("/auth")
+
+ }
+
+ },
+ refetchOnWindowFocus: false,
+
+ ...options
+
+ }
+ );
+}
+
+export default useGetSingleQuery;
diff --git a/src/api/helper/useGetWithFillter.ts b/src/api/helper/useGetWithFillter.ts
new file mode 100644
index 0000000..448e548
--- /dev/null
+++ b/src/api/helper/useGetWithFillter.ts
@@ -0,0 +1,22 @@
+import { useQuery } from 'react-query';
+import useAxios from './useAxios';
+
+export default function useGetQueryPagination(KEY: string | string[], Api: string, options: any = {}) {
+ const axios = useAxios();
+ const pagination = options;
+
+ return useQuery(
+ [ KEY], async () => {
+ const response = await axios.get(Api + pagination );
+ return response.data;
+ },
+ {
+ onError: (error:any) => {
+
+ },
+
+
+ }
+ );
+}
+
diff --git a/src/api/helper/useToggleStatus.ts b/src/api/helper/useToggleStatus.ts
new file mode 100644
index 0000000..0ef86bb
--- /dev/null
+++ b/src/api/helper/useToggleStatus.ts
@@ -0,0 +1,32 @@
+import { useQueryClient, useMutation } from "react-query";
+import { toast } from "react-toastify";
+import { useTranslation } from "react-i18next";
+import useAxios from "./useAxios";
+
+export const useToggleStatus = (key:any, url:any, object_id:any) => {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const [t] = useTranslation();
+
+ return useMutation(
+ async ({ id, new_status }:any) => {
+ const { data } = await axios.post(url, {
+ [object_id]: id,
+ new_status,
+ });
+ return { ...data, id, new_status };
+ },
+ {
+ onSuccess: ({ message, id, new_status }) => {
+ toast.success(message || t("toggle_success"));
+
+ queryClient.invalidateQueries([key]);
+ },
+ onError: (err:any) => {
+ const message = err?.response?.data?.message || t("toggle_failed");
+ toast.error(message);
+ // validateSession(err.response);
+ },
+ }
+ );
+};
diff --git a/src/api/helper/useUpdateMutation.ts b/src/api/helper/useUpdateMutation.ts
new file mode 100644
index 0000000..29b258f
--- /dev/null
+++ b/src/api/helper/useUpdateMutation.ts
@@ -0,0 +1,58 @@
+import { useQueryClient, useMutation, UseMutationResult } from "react-query";
+import { toast } from "react-toastify";
+import useAxios from "./useAxios";
+import { useTranslation } from "react-i18next";
+import { useParams } from "react-router-dom";
+
+type AxiosResponse = {
+ message: string;
+ // Add other properties as needed
+};
+
+const useUpdateMutation = (
+ key: string,
+ url: string,
+ toastMessage: boolean = false,
+ method?:string
+): UseMutationResult => {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const [t] = useTranslation();
+ const {id}= useParams()
+
+ return useMutation(
+ async (dataToSend) => {
+ if(method === "put"){
+ const { data } = await axios.put(url+"/"+id, dataToSend );
+ return data;
+ }else{
+ const { data } = await axios.post(url+"/"+id, dataToSend,{
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ });
+ return data;
+ }
+
+
+
+ },
+ {
+ onSuccess: (data) => {
+ if (toastMessage) {
+ toast.success(data.message || t("updated_successfully"));
+ }
+ queryClient.invalidateQueries([key]);
+ },
+ onError: (err:any) => {
+ const message = err?.response?.data?.message || t("failed_to_update_data");
+ toast.error(message);
+
+
+ // validateSession(err.response);
+ },
+ }
+ );
+};
+
+export default useUpdateMutation;
diff --git a/src/api/helper/useUpdateMutationById.ts b/src/api/helper/useUpdateMutationById.ts
new file mode 100644
index 0000000..1d5ed72
--- /dev/null
+++ b/src/api/helper/useUpdateMutationById.ts
@@ -0,0 +1,57 @@
+import { useQueryClient, useMutation, UseMutationResult } from "react-query";
+import { toast } from "react-toastify";
+import useAxios from "./useAxios";
+import { useTranslation } from "react-i18next";
+import { useParams } from "react-router-dom";
+
+type AxiosResponse = {
+ message: string;
+ // Add other properties as needed
+};
+
+const useUpdateMutationById = (
+ key: string,
+ url: string,
+ toastMessage: boolean = false,
+ method?:string
+): UseMutationResult => {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const [t] = useTranslation();
+
+ return useMutation(
+ async (dataToSend:any) => {
+ if(method === "put"){
+ const { data } = await axios.put(url+"/"+dataToSend?.id, dataToSend );
+ return data;
+ }else{
+ const { data } = await axios.post(url+"/"+dataToSend?.id, dataToSend,{
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ });
+ return data;
+ }
+
+
+
+ },
+ {
+ onSuccess: (data) => {
+ if (toastMessage) {
+ toast.success(data.message || t("updated_successfully"));
+ }
+ queryClient.invalidateQueries([key]);
+ },
+ onError: (err:any) => {
+ const message = err?.response?.data?.message || t("failed_to_update_data");
+ toast.error(message);
+
+
+ // validateSession(err.response);
+ },
+ }
+ );
+};
+
+export default useUpdateMutationById;
diff --git a/src/api/helper/useUpdateMutationPut.ts b/src/api/helper/useUpdateMutationPut.ts
new file mode 100644
index 0000000..bac1190
--- /dev/null
+++ b/src/api/helper/useUpdateMutationPut.ts
@@ -0,0 +1,52 @@
+import { useQueryClient, useMutation, UseMutationResult } from "react-query";
+import { toast } from "react-toastify";
+import useAxios from "./useAxios";
+import { useTranslation } from "react-i18next";
+import { useParams } from "react-router-dom";
+
+type AxiosResponse = {
+ message: string;
+ // Add other properties as needed
+};
+
+const useUpdateMutationPost = (
+ key: string,
+ url: string,
+ toastMessage: boolean = true,
+ method?:string
+): UseMutationResult => {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const [t] = useTranslation();
+ const {id}= useParams()
+
+ return useMutation(
+ async (dataToSend) => {
+
+ const { data } = await axios.post(url+"/"+id, dataToSend,{
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ });
+ return data;
+
+ },
+ {
+ onSuccess: (data) => {
+ if (toastMessage) {
+ toast.success(data.message || t("updated_successfully"));
+ }
+ queryClient.invalidateQueries([key]);
+ },
+ onError: (err:any) => {
+ const message = err?.response?.data?.message || t("failed_to_update_data");
+ toast.error(message);
+
+
+ // validateSession(err.response);
+ },
+ }
+ );
+};
+
+export default useUpdateMutationPost;
diff --git a/src/api/helper/useUploadWithProgress.ts b/src/api/helper/useUploadWithProgress.ts
new file mode 100644
index 0000000..00db02a
--- /dev/null
+++ b/src/api/helper/useUploadWithProgress.ts
@@ -0,0 +1,75 @@
+import { useState } from "react";
+import { useQueryClient, useMutation, MutationFunction } from "react-query";
+import { toast } from "react-toastify";
+import useAxios from "./useAxios";
+import { AxiosResponse } from "axios";
+import { useTranslation } from "react-i18next";
+import { QueryStatusEnum } from "../../config/QueryStatus";
+// import { validateSession } from "./validateSession";
+
+interface UploadWithProgressReturnType {
+ percentCompleted: number;
+ mutate: MutationFunction;
+ isLoading: boolean;
+ isError: boolean;
+ error: unknown;
+ isSuccess:boolean,
+ value:any,
+ status : QueryStatusEnum
+}
+
+export const useUploadWithProgress = (
+ key: string,
+ url: string
+): UploadWithProgressReturnType => {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const [percentCompleted, setPercentCompleted] = useState(0.0);
+ const {t} = useTranslation();
+ const mutation = useMutation<
+ AxiosResponse,
+ unknown,
+ any,
+ {
+ onSuccess: (data: AxiosResponse) => void;
+ onError: (error: unknown) => void;
+ }
+ >(
+ async (dataToSend) => {
+ setPercentCompleted(0.0);
+ const { data } = await axios.post(url, dataToSend, {
+ onUploadProgress: (event:any) => {
+ console.log();
+
+ if (event?.event?.lengthComputable) {
+ setPercentCompleted(Math.round((event.loaded * 100) / event.total));
+ }
+ },
+ });
+ return data;
+ },
+ {
+ onSuccess: ({ data }) => {
+ toast.success(data.message || t("_messages.success.upload"));
+ queryClient.invalidateQueries([key]);
+ },
+ onError: (err:any) => {
+ const message =
+ err?.response?.data?.message || t("_messages.error.upload");
+ toast.error(message);
+ // validateSession(err.response);
+ },
+ }
+ );
+
+ return {
+ percentCompleted,
+ value:percentCompleted,
+ mutate: mutation.mutate as MutationFunction,
+ isLoading: mutation.isLoading,
+ isError: mutation.isError,
+ error: mutation.error,
+ isSuccess :mutation.isSuccess,
+ status : mutation.status as QueryStatusEnum
+ };
+};
\ No newline at end of file
diff --git a/src/asset/logo/MainLogo.png b/src/asset/logo/MainLogo.png
new file mode 100644
index 0000000..84d4dcb
Binary files /dev/null and b/src/asset/logo/MainLogo.png differ
diff --git a/src/config/AppKey.ts b/src/config/AppKey.ts
new file mode 100644
index 0000000..81f1533
--- /dev/null
+++ b/src/config/AppKey.ts
@@ -0,0 +1,12 @@
+
+
+
+const PROJECT_NAME = "E-Menu_DAHBOARD"
+
+export const TOKEN_KEY = PROJECT_NAME + "_TOKEN"
+export const TOKEN_KEY_SOCKET = PROJECT_NAME + "_SOKCET_TOKEN"
+
+export const USER_KEY = PROJECT_NAME + "_USER"
+
+
+/// 1825|laravel_sanctum_RpRqXDf1jg1Jgb0VjnJcUzPpSmX46PD7h8jB8ag372d0778a
diff --git a/src/config/QueryStatus.ts b/src/config/QueryStatus.ts
new file mode 100644
index 0000000..2351251
--- /dev/null
+++ b/src/config/QueryStatus.ts
@@ -0,0 +1,8 @@
+
+
+export enum QueryStatusEnum {
+ LOADING="loading",
+ ERROR ="error",
+ SUCCESS="success",
+ IDLE ="idle"
+}
diff --git a/src/config/RoleConfige.ts b/src/config/RoleConfige.ts
new file mode 100644
index 0000000..b445160
--- /dev/null
+++ b/src/config/RoleConfige.ts
@@ -0,0 +1,7 @@
+export const VIEWER: string = "viewer";
+export const VENDOR: string = "vendor";
+export const ADMIN: string = "admin";
+export const SUPER_ADMIN: string = "Super Admin";
+export const CLIENT: string = "client";
+
+export const Roles: string[] = [VIEWER, VENDOR, ADMIN, SUPER_ADMIN];
\ No newline at end of file
diff --git a/src/enums/ChartTypeEnum.ts b/src/enums/ChartTypeEnum.ts
new file mode 100644
index 0000000..79a6c3e
--- /dev/null
+++ b/src/enums/ChartTypeEnum.ts
@@ -0,0 +1,14 @@
+export enum ChartTypeEnum {
+ LINE = "line",
+ AREA = "area",
+ BAR = "bar",
+ RADIAL = "radialBar",
+ PIE = "pie",
+ DONUT = "donut",
+ SCATTER = "scatter",
+ BUBBLE = "bubble",
+ HEATMAP = "heatmap",
+ CANDLESTICK = "candlestick",
+ }
+
+
\ No newline at end of file
diff --git a/src/enums/SocketEventEnum.ts b/src/enums/SocketEventEnum.ts
new file mode 100644
index 0000000..bcded09
--- /dev/null
+++ b/src/enums/SocketEventEnum.ts
@@ -0,0 +1,15 @@
+
+
+
+export enum SocketEventLisntEnum {
+
+ SOCKET_DEBUG = 'dashboard_debug' ,
+ SOCKET_NEW_USER = 'new_driver_come_online' ,
+ SOCKET_UPDATE_USER = 'update_driver_online' ,
+ SOCKET_REMOVE_USER = 'remove_driver_from_online' ,
+
+ SOCKET_NEW_ORDER = 'new_order_come_pendding' ,
+ SOCKET_ACCEPTE_ORDER = 'order_accepted_by_driver' ,
+ SOCKET_START_ORDER = 'order_start' ,
+
+}
\ No newline at end of file
diff --git a/src/index.tsx b/src/index.tsx
new file mode 100644
index 0000000..1be6dc6
--- /dev/null
+++ b/src/index.tsx
@@ -0,0 +1,15 @@
+import App from './App';
+import 'bootstrap/dist/css/bootstrap.min.css';
+import './Styles/AppStyle/Import.scss'
+import 'react-tabs/style/react-tabs.css';
+import { createRoot } from "react-dom/client";
+import ProviderContainer from './ProviderContainer';
+
+const root = createRoot(document.getElementById("root") as HTMLElement);
+root.render(
+
+
+
+
+
+);
\ No newline at end of file
diff --git a/src/lib/ReactQueryProvider.tsx b/src/lib/ReactQueryProvider.tsx
new file mode 100644
index 0000000..4b56401
--- /dev/null
+++ b/src/lib/ReactQueryProvider.tsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import { QueryClient, QueryClientProvider } from 'react-query'
+
+function QueryProvider({ children }: any) {
+ const queryClient = new QueryClient()
+
+ return (
+
+ {children}
+
+
+ )
+}
+
+export default QueryProvider
+
+
diff --git a/src/lib/SocketProvider.tsx b/src/lib/SocketProvider.tsx
new file mode 100644
index 0000000..aa00e9d
--- /dev/null
+++ b/src/lib/SocketProvider.tsx
@@ -0,0 +1,37 @@
+
+import { Socket, io } from 'socket.io-client';
+import { TOKEN_KEY_SOCKET } from '../config/AppKey';
+
+
+export const BASE_URL_SOCKET = 'http://192.168.1.14:8001/';
+var socket :Socket | null = null ;
+
+
+function InitSocket(){
+
+
+
+ if (!socket){
+ socket = io(BASE_URL_SOCKET , {
+ transports:['websocket'],
+ autoConnect:true,
+ query:{
+ token:localStorage.getItem(TOKEN_KEY_SOCKET),
+
+ }
+ });
+ }
+}
+
+export const disconnectSocket = ()=>{
+
+ socket?.disconnect();
+ socket = null;
+}
+export const getScoket = ()=>{
+
+ InitSocket();
+ return socket;
+}
+
+
diff --git a/src/lib/ToastProvider.tsx b/src/lib/ToastProvider.tsx
new file mode 100644
index 0000000..b2e9c27
--- /dev/null
+++ b/src/lib/ToastProvider.tsx
@@ -0,0 +1,27 @@
+import React from 'react'
+import { ToastContainer } from 'react-toastify'
+import 'react-toastify/dist/ReactToastify.css';
+
+function ToastProvider({ children }: any) {
+ let What_the_language = localStorage.getItem('language') ?? "en";
+
+ return (
+ <>
+
+ {children}
+ >
+ )
+}
+
+export default ToastProvider
\ No newline at end of file
diff --git a/src/lib/state mangment/AuthState.ts b/src/lib/state mangment/AuthState.ts
new file mode 100644
index 0000000..b2bd147
--- /dev/null
+++ b/src/lib/state mangment/AuthState.ts
@@ -0,0 +1,51 @@
+import {create} from 'zustand';
+import { TOKEN_KEY, TOKEN_KEY_SOCKET, USER_KEY } from '../../config/AppKey';
+
+interface LoginResponse {
+ token:string ,
+ "admin": any,
+ token_node:string
+}
+
+interface AuthStore {
+ user: any | null |undefined;
+ token:string |null | undefined;
+ isAuthenticated: boolean;
+ login: (userData: LoginResponse) => Promise;
+ logout: () => Promise;
+}
+
+const useAuthState = create((set) => {
+
+ const storedUser :any = localStorage.getItem(USER_KEY) ;
+
+ const storedToken = localStorage.getItem(TOKEN_KEY);
+ const initialUser = (storedUser && storedUser !== 'undefined') ? JSON.parse(storedUser) : null;
+
+ return {
+ user: initialUser,
+ isAuthenticated: !!storedToken,
+ token:storedToken,
+ login: async (userData) => {
+ console.log(userData);
+ localStorage.setItem(TOKEN_KEY , userData.token)
+
+ localStorage.setItem(USER_KEY , JSON.stringify(userData.admin))
+
+ set((state)=>({user:userData.admin , isAuthenticated:true , token:userData.token}))
+
+ },
+ logout: async () => {
+
+ localStorage.removeItem(TOKEN_KEY )
+ localStorage.removeItem(TOKEN_KEY_SOCKET )
+
+ localStorage.removeItem(USER_KEY )
+ set((state)=>({user:null , isAuthenticated:false , token:null}))
+
+
+ },
+ };
+});
+
+export default useAuthState;
diff --git a/src/lib/state mangment/LayoutPagestate.ts b/src/lib/state mangment/LayoutPagestate.ts
new file mode 100644
index 0000000..db1c4b5
--- /dev/null
+++ b/src/lib/state mangment/LayoutPagestate.ts
@@ -0,0 +1,29 @@
+import {create} from 'zustand'
+
+interface ModelState {
+ isOpenAddModel: boolean;
+ isOpenEditModel: boolean;
+ objectToEdit: any;
+ isThemChanged:any;
+ setThemChange :()=> void ;
+ setIsOpenAddModel: () => void;
+ setIsOpenEditModel: () => void;
+ CloseAllModal: () => void;
+ setObjectToEdit: (data: any) => void;
+}
+
+export const usePageState = create((set) => ({
+ isOpenAddModel: false,
+ isOpenEditModel: false,
+ objectToEdit: null,
+ isThemChanged:false,
+ setThemChange: () =>
+ set((state) => ({ isThemChanged: !state.isThemChanged })),
+ setIsOpenAddModel: () =>
+ set((state) => ({ isOpenAddModel: !state.isOpenAddModel })),
+ setIsOpenEditModel: () =>
+ set((state) => ({ isOpenEditModel: !state.isOpenEditModel })),
+ CloseAllModal: () =>
+ set((state) => ({ isOpenAddModel: false, isOpenEditModel: false })),
+ setObjectToEdit: (data) => set(() => ({ objectToEdit: data })),
+}));
diff --git a/src/lib/state mangment/Pages/Products.ts b/src/lib/state mangment/Pages/Products.ts
new file mode 100644
index 0000000..4679b15
--- /dev/null
+++ b/src/lib/state mangment/Pages/Products.ts
@@ -0,0 +1,15 @@
+import {create} from 'zustand'
+
+interface ProductState {
+ TapItems:any;
+ setTapItems :any ;
+ TapItemValues:any;
+ setTapItemValues :any ;
+}
+
+export const useProductVarianState = create((set) => ({
+ TapItems:[],
+ setTapItems: (data : any) => set(() => ({ TapItems: data })),
+ TapItemValues:[],
+ setTapItemValues: (data : any) => set(() => ({ TapItemValues: data })),
+}));
diff --git a/src/lib/state mangment/driver&customer/ModelState.tsx b/src/lib/state mangment/driver&customer/ModelState.tsx
new file mode 100644
index 0000000..4a4ee9c
--- /dev/null
+++ b/src/lib/state mangment/driver&customer/ModelState.tsx
@@ -0,0 +1,33 @@
+import {create} from 'zustand'
+
+interface ModalState {
+
+ isOpenBlock:boolean ,
+ isOpenGift:boolean ,
+ isOpenUnBlock:boolean ,
+
+ setIsopenBlock :() => void ,
+ setIsopenUnBlock :() => void ,
+ setIsopenGift :() => void ,
+
+ setObjectId :(data:number) => void ,
+ objectID:number
+
+}
+
+export const useCommonModelState = create((set) => ({
+
+ isOpenBlock:false,
+ isOpenGift:false,
+ isOpenUnBlock:false,
+
+ setIsopenBlock: () =>
+ set((state) => ({ isOpenBlock: !state.isOpenBlock })),
+ setIsopenUnBlock: () =>
+ set((state) => ({ isOpenUnBlock: !state.isOpenUnBlock })),
+ setIsopenGift: () =>
+ set((state) => ({ isOpenGift: !state.isOpenGift })),
+ setObjectId: (data:number) =>
+ set((state) => ({ objectID: data })),
+ objectID:0
+}));
diff --git a/src/translate/ar.json b/src/translate/ar.json
new file mode 100644
index 0000000..e7f7553
--- /dev/null
+++ b/src/translate/ar.json
@@ -0,0 +1,191 @@
+{
+ "Ar": "عربي",
+ "En": "انكليزي",
+ "Arabic": "عربي",
+ "English": "إنجليزي",
+ "German" : "ألمانية",
+ "Login": "تسجيل الدخول",
+ "Welcome back, please login to your account.": "مرحبًا بك مرة أخرى ، يرجى تسجيل الدخول إلى حسابك.",
+ "Username": "اسم المستخدم",
+ "Password": "كلمة المرور",
+ "Sign in": "تسجيل الدخول",
+ "Point © 2022 | All Rights Reserved": "Point © 2022 |كل الحقوق محفوظة",
+ "unknown": "مجهول",
+ "super admin": "مشرف سوبر",
+ "admin": "مسؤل",
+ "Home": "الصفحة الرئيسية",
+ "example": "مثال",
+ "Log Out": "تسجيل خروج",
+ "Example": "مثال",
+ "Add": "اضافة",
+ "username": "اسم ",
+ "password": "كلمة المرور ",
+ "name": "اسم",
+ "email": "الحساب",
+ "cancel": "الغاء",
+ "edit": "تعديل",
+ "light": "وضع النهاري",
+ "dark": "وضع اليلي",
+ "Categories": "الفئات",
+ "Products": "المنتجات",
+ "Order": "الطلب",
+ "Coupon": "القسيمة",
+ "Slider": "الشريحة",
+ "Product_in_your_Application": "المنتج في تطبيقك",
+ "categories_in_your_Application": "الفئات في تطبيقك",
+ "Order_in_your_Application": "الطلب في تطبيقك",
+ "You_have": "لديك",
+ "January": "يناير",
+ "February": "فبراير",
+ "March": "مارس",
+ "April": "أبريل",
+ "London": "لندن",
+ "Paris": "باريس",
+ "New York": "نيويورك",
+ "Seoul": "سيول",
+ "image": "صورة",
+ "parent_id": "الأب",
+ "product_count": "عدد المنتجات",
+ "basicinfo": "معلومات أساسية",
+ "view_information": "عرض المعلومات",
+ "back": "العودة",
+ "price": "السعر",
+ "description": "الوصف",
+ "favorite": "المفضلة",
+ "main_photo": "الصورة الرئيسية",
+ "category_id": " الفئة",
+ "order_code": "رمز الطلب",
+ "status": "الحالة",
+ "total": "المجموع",
+ "order_id": " الطلب",
+ "customer_name": "اسم العميل",
+ "customer_phone_number": "رقم هاتف العميل",
+ "order_created_at": "تم إنشاء الطلب في",
+ "address": "عنوان",
+ "country": "بلد",
+ "note": "ملاحظة",
+ "categories": "الفئات",
+ "coupon": "القسيمة",
+ "orders": "الطلبات",
+ "products": "المنتجات",
+ "slider": "الشريحة",
+ "discount_type": "نوع الخصم",
+ "coupon_type": "نوع الكوبون",
+ "code": "الكود",
+ "coupon_value": "قيمة الكوبون",
+ "view_information_filed_fill_sucsessfully": "تم ملء حقل معلومات العرض بنجاح",
+ "category": "الفئة",
+ "View_information": "عرض المعلومات",
+ "VarianInfo": "معلومات المتغير",
+ "Base_info": "المعلومات الأساسية",
+ "name_ar": "الاسم بالعربية",
+ "name_en": "الاسم بالإنجليزية",
+ "name_de": "الاسم بالألمانية",
+ "description_ar": "الوصف بالعربية",
+ "description_en": "الوصف بالإنجليزية",
+ "description_de": "الوصف بالألمانية",
+ "upload_image": "تحميل الصورة",
+ "photo": "الصورة",
+ "admin_note": "ملاحظة الإدارة",
+ "state": "الحالة",
+ "title": "العنوان",
+ "totals": "المجموعات",
+ "delivery_fee": "رسوم التوصيل",
+ "overall_total": "المجموع الكلي",
+ "sub_total": "المجموع الفرعي",
+ "quantity": "الكمية",
+ "active_from_to": "النشاط من/إلى",
+ "maximum_number_of_uses": "الحد الأقصى لعدد الاستخدامات",
+ "minimum_total_to_order": "الحد الأدنى للإجمالي للطلب",
+ "maximum_number_of_uses_per_user": "الحد الأقصى لعدد الاستخدامات لكل مستخدم",
+ "product_item": "عنصر المنتج",
+ "categories_item": " عنصر الفئات",
+ "variables": "المتغيرات",
+ "Information": "المعلومات",
+ "key": "المفتاح",
+ "Description": "الوصف",
+ "Add Another Item": "إضافة عنصر آخر",
+ "images": "الصور",
+ "no_records": "لا توجد سجلات",
+ "Total": "المجموع",
+ "items": "عناصر",
+ "search": "بحث",
+ "required_name": "جميع حقول الاسم مطلوبة. في السمة",
+ "required_description": "جميع حقول الوصف مطلوبة. في السمة",
+ "required_main_photo": "حقل الصورة الرئيسية مطلوب في السمة",
+ "required_price": "حقل السعر مطلوب في السمة",
+ "required_type": "حقل النوع مطلوب. في السمة",
+ "required_image": "حقل الصورة مطلوب في القيمة",
+ "required_color": "يجب أن يكون حقل اللون قيمة هكس",
+ "required_text": "جميع حقول القيمة مطلوبة.",
+ "BasicInfo": "المعلومات الأساسية",
+ "attributes": "السمات",
+ "Add New Attribute": "إضافة سمة جديدة",
+ "Attribute": "السمة",
+ "Value": "القيمة",
+ "Add New Variant": "إضافة متغير جديد",
+ "variant": "متغير",
+ "unique_error_names": "اسم فريد لكل سمة مطلوب",
+ "deliviration_estimated_time": "الوقت المقدر للتسليم",
+ "delivery_link": "رابط التسليم",
+ "delete_are_you_sure": "هل أنت متأكد أنك تريد الحذف؟",
+ "yes_delete_it": "نعم، احذفه",
+ "notification": "إشعار",
+ "users": "المستخدمون",
+ "body": "جسم",
+ "body_en": "الجسم (الإنجليزية)",
+ "body_ar": "الجسم (العربية)",
+ "body_de": "الجسم (الألمانية)",
+ "title_en": "العنوان (الإنجليزية)",
+ "title_ar": "العنوان (العربية)",
+ "title_de": "العنوان (الألمانية)",
+ "avatar": "الصورة الرمزية",
+ "added_successful": "تمت الإضافة بنجاح",
+ "failed_to_add_data": "فشلت عملية الإضافة",
+ "deleted_successfully": "تم الحذف بنجاح",
+ "updated_successfully": "تم التحديث بنجاح",
+ "Product_Count_in_your_Application": "عدد المنتجات في تطبيقك",
+ "productCount": "عدد المنتجات",
+ "user_in_your_Application": "المستخدمون في تطبيقك",
+ "userCount": "عدد المستخدمين",
+ "orderCount": "عدد الطلبات",
+ "order_count_in_your_Application": "عدد الطلبات في تطبيقك",
+ "month": "شهر",
+ "sorry_only_user_can_change_his_status": "عذرًا، فقط المستخدم يمكنه تغيير حالته.",
+ "create_notification": "إنشاء إشعار",
+ "SupportMessages": "رسائل الدعم",
+ "whatsApp": "واتساب",
+ "subject": "الموضوع",
+ "message": "الرسالة",
+ "EditDetails": "تعديل التفاصيل",
+ "OrderItems": "عناصر الطلب",
+ "reset": "إعادة تعيين",
+ "submit": "إرسال",
+ "errorPage": {
+ "networkError": "خطأ في الشبكة",
+ "checkAndModify": "يرجى التحقق من الشبكة الخاصة بك وإعادة تحميل الصفحة.",
+ "refetch": "إعادة تحميل الصفحة",
+ "goToHome": "الانتقال إلى الصفحة الرئيسية"
+ },
+ "value_en": "القيمة (الإنجليزية)",
+ "value_ar": "القيمة (العربية)",
+ "value_de": "القيمة (الألمانية)",
+ "type": "النوع",
+ "id": "المعرف",
+ "submite": "تقديم",
+ "PriceFrom": "السعر من",
+ "PriceTo": "السعر إلى",
+ "Pending Approve": "قيد الموافقة",
+ "Approved": "تمت الموافقة عليه",
+ "Rejected": "مرفوض",
+ "Pending Cancellation": "في انتظار الإلغاء",
+ "user_ids": "معرفات المستخدمين",
+ "user": "مستخدم",
+ "login_successful": "تسجيل الدخول ناجح",
+ "DateFrom": "تاريخ البدء",
+ "DateTo": "تاريخ الانتهاء"
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/translate/de.json b/src/translate/de.json
new file mode 100644
index 0000000..618b8e7
--- /dev/null
+++ b/src/translate/de.json
@@ -0,0 +1,191 @@
+{
+ "Ar": "Ar",
+ "En": "En",
+ "Arabic": "Arabisch",
+ "English": "Englisch",
+ "German": "Deutsch",
+ "Login": "Anmelden",
+ "Welcome back, please login to your account.": "Willkommen zurück, bitte melden Sie sich bei Ihrem Konto an.",
+ "Username": "Benutzername",
+ "Password": "Passwort",
+ "Sign in": "Einloggen",
+ "Point © 2022 | All Rights Reserved": "Point © 2022 | Alle Rechte vorbehalten",
+ "unknown": "unbekannt",
+ "super admin": "Superadmin",
+ "Home": "Startseite",
+ "example": "Beispiel",
+ "Log Out": "Abmelden",
+ "Example": "Beispiel",
+ "Add": "Hinzufügen",
+ "edit": "Bearbeiten",
+ "ligth": "Licht",
+ "dark": "Dunkel",
+ "Categories": "Kategorien",
+ "Products": "Produkte",
+ "Order": "Bestellung",
+ "Coupon": "Gutschein",
+ "Slider": "Schieberegler",
+ "Product_in_your_Application": "Produkt in Ihrer Anwendung",
+ "categories_in_your_Application": "Kategorien in Ihrer Anwendung",
+ "Order_in_your_Application": "Bestellung in Ihrer Anwendung",
+ "You_have": "Sie haben",
+ "January": "Januar",
+ "February": "Februar",
+ "March": "März",
+ "April": "April",
+ "London": "London",
+ "Paris": "Paris",
+ "New York": "New York",
+ "Seoul": "Seoul",
+ "name": "name",
+ "image": "bild",
+ "parent_id": "übergeordnete",
+ "product_count": "produktanzahl",
+ "basicinfo": "grundinfo",
+ "view_information": "information anzeigen",
+ "back": "zurück",
+ "price": "preis",
+ "description": "beschreibung",
+ "favorite": "favorit",
+ "main_photo": "hauptfoto",
+ "category_id": "kategorie",
+ "order_code": "bestellcode",
+ "email": "email",
+ "status": "status",
+ "total": "gesamt",
+ "order_id": "bestell",
+ "customer_name": "kundenname",
+ "customer_phone_number": "kunden telefonnummer",
+ "order_created_at": "bestellung erstellt am",
+ "address": "adresse",
+ "country": "land",
+ "note": "anmerkung",
+ "categories": "kategorien",
+ "coupon": "gutschein",
+ "orders": "bestellungen",
+ "products": "produkte",
+ "slider": "schieberegler",
+ "discount_type": "Rabatttyp",
+ "coupon_type": "Gutscheintyp",
+ "code": "Code",
+ "coupon_value": "Gutscheinwert",
+ "view_information_filed_fill_sucsessfully": "Anzeigeinformationsfeld erfolgreich ausgefüllt",
+ "category": "Kategorie",
+ "View_information": "Information anzeigen",
+ "VarianInfo": "Varianteninformation",
+ "Base_info": "Basisinformationen",
+ "name_ar": "Name (Arabisch)",
+ "name_en": "Name (Englisch)",
+ "name_de": "Name (Deutsch)",
+ "description_ar": "Beschreibung (Arabisch)",
+ "description_en": "Beschreibung (Englisch)",
+ "description_de": "Beschreibung (Deutsch)",
+ "upload_image": "Bild hochladen",
+ "images": "Bilder",
+ "photo": "Foto",
+ "admin_note": "Admin-Hinweis",
+ "state": "Status",
+ "title": "Titel",
+ "totals": "Summen",
+ "delivery_fee": "Liefergebühr",
+ "overall_total": "Gesamtsumme",
+ "sub_total": "Teilsumme",
+ "quantity": "Menge",
+ "active_from_to": "Aktiv von/bis",
+ "maximum_number_of_uses": "Maximale Anzahl von Verwendungen",
+ "minimum_total_to_order": "Mindestgesamtbestellung",
+ "maximum_number_of_uses_per_user": "Maximale Anzahl von Verwendungen pro Benutzer",
+ "product_item": "Produktartikel",
+ "categories_item": "der Kategorienartikel",
+ "variables": "Variablen",
+ "Information": "Informationen",
+ "key": "Schlüssel",
+ "Description": "Beschreibung",
+ "Add Another Item": "Weiteres Element hinzufügen",
+ "no_records": "Keine Datensätze",
+ "Total": "Insgesamt",
+ "items": "Artikel",
+ "search": "Suche",
+ "required_name": "Alle Namensfelder sind erforderlich. in Attribut",
+ "required_description": "Alle Beschreibungsfelder sind erforderlich. in Attribut",
+ "required_main_photo": "Hauptfoto-Feld ist in Attribut erforderlich",
+ "required_price": "Preisfeld ist in Attribut erforderlich",
+ "required_type": "Feldtyp ist erforderlich. in Attribut",
+ "required_image": "Bildfeld ist in Wert erforderlich",
+ "required_color": "Farbfeld muss ein Hex-Wert sein",
+ "required_text": "Alle Wertfelder sind erforderlich.",
+ "BasicInfo": "Grundlegende Informationen",
+ "attributes": "Attribute",
+ "Add New Attribute": "Neues Attribut hinzufügen",
+ "Attribute": "Attribut",
+ "Value": "Wert",
+ "Add New Variant": "Neue Variante hinzufügen",
+ "variant": "Variante",
+ "unique_error_names": "Einzigartiger Name für jede Eigenschaft ist erforderlich",
+ "deliviration_estimated_time": "Voraussichtliche Lieferzeit",
+ "delivery_link": "Lieferlink",
+ "delete_are_you_sure": "Möchten Sie wirklich löschen?",
+ "yes_delete_it": "Ja, löschen",
+ "cancel": "Abbrechen",
+ "notification": "Benachrichtigung",
+ "users": "Benutzer",
+ "body": "Körper",
+ "body_en": "Körper (Englisch)",
+ "body_ar": "Körper (Arabisch)",
+ "body_de": "Körper (Deutsch)",
+ "title_en": "Titel (Englisch)",
+ "title_ar": "Titel (Arabisch)",
+ "title_de": "Titel (Deutsch)",
+ "avatar": "Avatar",
+ "added_successful": "Erfolgreich hinzugefügt",
+ "failed_to_add_data": "Daten konnten nicht hinzugefügt werden",
+ "deleted_successfully": "Erfolgreich gelöscht",
+ "updated_successfully": "Erfolgreich aktualisiert",
+ "Product_Count_in_your_Application": "Anzahl der Produkte in Ihrer Anwendung",
+ "productCount": "Anzahl der Produkte",
+ "user_in_your_Application": "Benutzer in Ihrer Anwendung",
+ "userCount": "Anzahl der Benutzer",
+ "orderCount": "Anzahl der Bestellungen",
+ "order_count_in_your_Application": "Anzahl der Bestellungen in Ihrer Anwendung",
+ "month": "Monat",
+ "sorry_only_user_can_change_his_status": "Entschuldigung, nur der Benutzer kann seinen Status ändern.",
+ "create_notification": "Benachrichtigung erstellen",
+ "SupportMessages": "Support-Nachrichten",
+ "whatsApp": "WhatsApp",
+ "subject": "Betreff",
+ "message": "Nachricht",
+ "EditDetails": "Details bearbeiten",
+ "OrderItems": "Bestellpositionen",
+ "reset": "Zurücksetzen",
+ "submit": "Absenden",
+ "errorPage": {
+ "networkError": "Netzwerkfehler",
+ "checkAndModify": "Bitte überprüfen Sie Ihr Netzwerk und laden Sie die Seite erneut.",
+ "refetch": "Seite neu laden",
+ "goToHome": "Zum Startseite"
+ }
+,
+"value_en": "Wert (Englisch)",
+"value_ar": "Wert (Arabisch)",
+"value_de": "Wert (Deutsch)",
+"type": "Typ",
+"id": "ID",
+"submite": "Einreichen",
+"PriceFrom": "Preis ab",
+"PriceTo": "Preis bis",
+"Pending Approve": "Ausstehende Genehmigung",
+"Approved": "Genehmigt",
+"Rejected": "Abgelehnt",
+"Pending Cancellation": "Ausstehende Stornierung",
+"user_ids": "Benutzer-IDs",
+"user": "Benutzer",
+"login_successful": "Anmeldung erfolgreich",
+
+ "DateFrom": "Datum von",
+ "DateTo": "Datum bis"
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/translate/en.json b/src/translate/en.json
new file mode 100644
index 0000000..f473476
--- /dev/null
+++ b/src/translate/en.json
@@ -0,0 +1,191 @@
+{
+ "Ar": "Ar",
+ "En": "En",
+ "Arabic": "Arabic",
+ "English": "English",
+ "German": "German",
+ "Login": "Login",
+ "Welcome back, please login to your account.": "Welcome back, please login to your account.",
+ "Username": "Username",
+ "Password": "Password",
+ "Sign in": "Sign in",
+ "Point © 2022 | All Rights Reserved": "Point © 2022 | All Rights Reserved",
+ "unknown": "Unknown",
+ "super admin": "Super admin",
+ "Home": "Home",
+ "example": "Example",
+ "Log Out": "Log Out",
+ "Example": "Example",
+ "Add": "Add",
+ "edit": "Edit",
+ "ligth": "Light",
+ "dark": "Dark",
+ "Categories": "Categories",
+ "Products": "Products",
+ "Order": "Order",
+ "Coupon": "Coupon",
+ "Slider": "Slider",
+ "Product_in_your_Application": "Product in your Application",
+ "categories_in_your_Application": "Categories in your Application",
+ "Order_in_your_Application": "Order in your Application",
+ "You_have": "You have",
+ "January": "January",
+ "February": "February",
+ "March": "March",
+ "April": "April",
+ "London": "London",
+ "Paris": "Paris",
+ "New York": "New York",
+ "Seoul": "Seoul",
+ "name": "Name",
+ "image": "Image",
+ "parent_id": "Parent",
+ "product_count": "Product count",
+ "basicinfo": "Basic info",
+ "view_information": "View information",
+ "back": "Back",
+ "price": "Price",
+ "description": "Description",
+ "favorite": "Favorite",
+ "main_photo": "Main photo",
+ "category_id": "Category",
+ "order_code": "Order code",
+ "email": "Email",
+ "status": "Status",
+ "total": "Total",
+ "order_id": "Order",
+ "customer_name": "Customer name",
+ "customer_phone_number": "Customer phone number",
+ "order_created_at": "Order created at",
+ "address": "Address",
+ "country": "Country",
+ "note": "Note",
+ "categories": "Categories",
+ "coupon": "Coupon",
+ "orders": "Orders",
+ "products": "Products",
+ "slider": "Slider",
+ "discount_type": "Discount Type",
+ "coupon_type": "Coupon Type",
+ "code": "Code",
+ "coupon_value": "Coupon Value",
+ "view_information_filed_fill_sucsessfully": "View information field filled successfully",
+ "category": "Category",
+ "View_information": "View Information",
+ "VarianInfo": "Variant Information",
+ "Base_info": "Base Information",
+ "name_ar": "Name (Arabic)",
+ "name_en": "Name (English)",
+ "name_de": "Name (German)",
+ "description_ar": "Description (Arabic)",
+ "description_en": "Description (English)",
+ "description_de": "Description (German)",
+ "upload_image": "Upload Image",
+ "images": "Images",
+ "photo": "Photo",
+ "admin_note": "Admin Note",
+ "state": "State",
+ "title": "Title",
+ "totals": "Totals",
+ "delivery_fee": "Delivery Fee",
+ "overall_total": "Overall Total",
+ "sub_total": "Sub Total",
+ "quantity": "Quantity",
+ "active_from_to": "Active From/To",
+ "maximum_number_of_uses": "Maximum Number of Uses",
+ "minimum_total_to_order": "Minimum Total to Order",
+ "maximum_number_of_uses_per_user": "Maximum Number of Uses Per User",
+ "product_item": "Product Item",
+ "categories_item": "Categories Item",
+ "variables": "Variables",
+ "Information": "Information",
+ "key": "Key",
+ "Description": "Description",
+ "Add Another Item": "Add Another Item",
+ "no_records": "No records",
+ "Total": "Total",
+ "items": "Items",
+ "search": "Search",
+ "required_name": "All Name Fields Are Required. in attribute",
+ "required_description": "All Description Fields Are Required. in attribute",
+ "required_main_photo": "Main Photo Field Is Required in attribute",
+ "required_price": "Price Field Is Required in attribute",
+ "required_type": "Type Field Is Required. in attribute",
+ "required_image": "Image Field Is Required in Value",
+ "required_color": "Color Field Must be a Hex value",
+ "required_text": "All value Fields Are Required.",
+ "BasicInfo": "Basic Info",
+ "attributes": "Attributes",
+ "Add New Attribute": "Add New Attribute",
+ "Attribute": "Attribute",
+ "Value": "Value",
+ "Items": "Items",
+ "Search": "Search",
+ "Basicinfo": "Basic Info",
+ "Attributes": "Attributes",
+ "Add New Variant": "Add New Variant",
+ "variant": "Variant",
+ "unique_error_names": "Unique name for each attribute is required",
+ "deliviration_estimated_time": "Delivery Estimated Time",
+ "delivery_link": "Delivery Link",
+ "delete_are_you_sure": "Are you sure you want to delete?",
+ "yes_delete_it": "Yes, delete it",
+ "cancel": "Cancel",
+ "required_error":"required_error",
+ "notification": "Notification",
+ "users": "Users",
+ "body": "Body",
+ "body_en": "Body (English)",
+ "body_ar": "Body (Arabic)",
+ "body_de": "Body (German)",
+ "title_en": "Title (English)",
+ "title_ar": "Title (Arabic)",
+ "title_de": "Title (German)",
+ "avatar": "Avatar",
+ "added_successful": "Added successful",
+ "failed_to_add_data": "Failed to add data",
+ "deleted_successfully": "Deleted successfully",
+ "updated_successfully": "updated successfully",
+ "Product_Count_in_your_Application": "Number of Products in Your Application",
+ "productCount": "Count of Products",
+ "user_in_your_Application": "Users in Your Application",
+ "userCount": "Count of Users",
+ "orderCount": "Count of Orders",
+ "order_count_in_your_Application": "Number of Orders in Your Application",
+ "month": "Month",
+ "sorry_only_user_can_change_his_status": "Sorry, only the user can change their status.",
+ "create_notification": "Create Notification",
+ "SupportMessages": "Support Messages",
+ "whatsApp": "WhatsApp",
+ "subject": "Subject",
+ "message": "Message",
+ "EditDetails": "Edit Details",
+ "OrderItems": "Order Items",
+ "reset": "Reset",
+ "submit": "Submit",
+ "errorPage": {
+ "networkError": "Network Error",
+ "checkAndModify": "Please check your network and refetch the page.",
+ "refetch": "Refetch Page",
+ "goToHome": "Go to Home"
+ }
+,
+"value_en": "Value (English)",
+"value_ar": "Value (Arabic)",
+"value_de": "Value (German)",
+"type": "Type",
+"id": "ID",
+"submite": "Submit",
+"PriceFrom": "Price From",
+"PriceTo": "Price To",
+"Pending Approve": "Pending Approve",
+"Approved": "Approved",
+"Rejected": "Rejected",
+"Pending Cancellation": "Pending Cancellation",
+"user_ids": "User IDs",
+ "user": "User",
+ "login_successful": "Login successful",
+ "DateFrom": "Date From",
+ "DateTo": "Date To"
+
+}
\ No newline at end of file
diff --git a/src/translate/text b/src/translate/text
new file mode 100644
index 0000000..928285b
--- /dev/null
+++ b/src/translate/text
@@ -0,0 +1,11 @@
+value_en
+value_ar
+value_de
+type
+id
+
+submite
+PriceFrom
+PriceTo
+PriceFrom
+PriceTo
\ No newline at end of file
diff --git a/src/types/SocketEvent.ts b/src/types/SocketEvent.ts
new file mode 100644
index 0000000..55b613f
--- /dev/null
+++ b/src/types/SocketEvent.ts
@@ -0,0 +1,8 @@
+
+
+export interface SocketDashboardDebugDataEvent {
+ event :string ,
+ socket_id :string ,
+ room ?: string | null ,
+ data : any
+}
\ No newline at end of file
diff --git a/src/types/User.ts b/src/types/User.ts
new file mode 100644
index 0000000..e8c3788
--- /dev/null
+++ b/src/types/User.ts
@@ -0,0 +1,21 @@
+
+export interface IUser{
+ "id": number ,
+ "full_name": string ,
+ "email": string ,
+ "phone": string ,
+ "is_verified": number,
+ "created_at": string ,
+ "updated_at": string,
+ "stripe_id": any,
+ "pm_type": any,
+ "pm_last_four": any,
+ "trial_ends_at": any,
+ "user_uid": any,
+ "sms_code": any,
+ "messageID": any,
+ "insurance_amount": number ,
+ "insurance_payment_id": any,
+ "role_type": string
+
+}
\ No newline at end of file
diff --git a/src/utils/Array/ArrayToObjectFormik.ts b/src/utils/Array/ArrayToObjectFormik.ts
new file mode 100644
index 0000000..5c11d90
--- /dev/null
+++ b/src/utils/Array/ArrayToObjectFormik.ts
@@ -0,0 +1,26 @@
+export function objectToArray(obj:any) {
+ // Initialize an empty array to store the result
+ const result = [] as any ;
+
+ // Iterate over the keys of the object
+ for (const key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ // Extract the index from the key
+ const index = parseInt(key.split('.')[0]);
+
+ // Get the attribute name from the key
+ const attributeName = key.split('.')[1];
+
+ // If the index does not exist in the result array, create a new object
+ if (!result[index]) {
+ result[index] = {};
+ }
+
+
+ // Set the attribute value in the result object
+ result[index][attributeName] = obj[key];
+ }
+ }
+
+ return result;
+ }
\ No newline at end of file
diff --git a/src/utils/Array/changeShapeInfo.tsx b/src/utils/Array/changeShapeInfo.tsx
new file mode 100644
index 0000000..0908eb2
--- /dev/null
+++ b/src/utils/Array/changeShapeInfo.tsx
@@ -0,0 +1,14 @@
+export function changeShapeInfo(originalObject: any) {
+ const transformedObject: any = {};
+
+ for (const key in originalObject) {
+ if (originalObject.hasOwnProperty(key)) {
+ const index = key.split('.')[0]; // Extract index from key
+ const attribute = key.split('.')[1]; // Extract attribute from key
+
+ transformedObject[originalObject[`${index}.key`]] = originalObject[`${index}.Description`];
+ }
+ }
+
+ return transformedObject
+}
\ No newline at end of file
diff --git a/src/utils/Array/filterUndefinedAndEmpty.ts b/src/utils/Array/filterUndefinedAndEmpty.ts
new file mode 100644
index 0000000..c0982ce
--- /dev/null
+++ b/src/utils/Array/filterUndefinedAndEmpty.ts
@@ -0,0 +1,5 @@
+const filterUndefinedAndEmpty = (array:any) => {
+ return array?.filter((data:any) => data !== undefined && Object.keys(data).length !== 0);
+ };
+
+ export default filterUndefinedAndEmpty;
\ No newline at end of file
diff --git a/src/utils/Array/getInfoKeyAndDescriptions.ts b/src/utils/Array/getInfoKeyAndDescriptions.ts
new file mode 100644
index 0000000..8ff163f
--- /dev/null
+++ b/src/utils/Array/getInfoKeyAndDescriptions.ts
@@ -0,0 +1,12 @@
+export function convertToObject(obj:any) {
+ const newObj = {} as any;
+ for (const key in obj) {
+ if (key.includes('.Key')) {
+ const newKey = obj[key];
+ const valueKey = key.replace('.Key', '.Description');
+ const value = obj[valueKey];
+ newObj[newKey] = value;
+ }
+ }
+ return newObj;
+}
\ No newline at end of file
diff --git a/src/utils/Date/ChangeFormat.ts b/src/utils/Date/ChangeFormat.ts
new file mode 100644
index 0000000..311775f
--- /dev/null
+++ b/src/utils/Date/ChangeFormat.ts
@@ -0,0 +1,5 @@
+export function ChangeformatDate(dateString:string) {
+ const dateObject = new Date(dateString);
+ const formattedDate = `${dateObject.toLocaleDateString()} ${dateObject.toLocaleTimeString()}`;
+ return formattedDate;
+}
\ No newline at end of file
diff --git a/src/utils/colors/getPrimaryColor.ts b/src/utils/colors/getPrimaryColor.ts
new file mode 100644
index 0000000..4f86548
--- /dev/null
+++ b/src/utils/colors/getPrimaryColor.ts
@@ -0,0 +1,3 @@
+
+
+export const getPrimaryColor = ()=>getComputedStyle(document.querySelector(':root')as any )?.getPropertyValue('--primary')
diff --git a/src/utils/language/mapTranslatedProperties.tsx b/src/utils/language/mapTranslatedProperties.tsx
new file mode 100644
index 0000000..e91b645
--- /dev/null
+++ b/src/utils/language/mapTranslatedProperties.tsx
@@ -0,0 +1,27 @@
+export const mapTranslatedProperties = (
+ arrayOfDetails :any,
+ properties:any ,
+ language_id : '1'|'2' |1 |2
+ ) => {
+ if (!arrayOfDetails || !properties || !language_id) return "";
+ if (Array.isArray(arrayOfDetails) && arrayOfDetails.length === 0) return "";
+
+ const target = arrayOfDetails.find(
+ (item:any) => item.language_id === language_id
+ );
+ if (!target) {
+ return "";
+ }
+
+ if (!Array.isArray(properties)) {
+ return target[properties];
+ }
+
+ // [prop1, prop2, prop3, ....] is passed
+ const ret:any = {};
+ properties.forEach((prop:string) => {
+ ret[prop] = target[prop];
+ });
+ return ret;
+ };
+
\ No newline at end of file
diff --git a/src/zustand/Modal.ts b/src/zustand/Modal.ts
new file mode 100644
index 0000000..97cd522
--- /dev/null
+++ b/src/zustand/Modal.ts
@@ -0,0 +1,15 @@
+import {create} from 'zustand'
+
+interface ModalState {
+ isOpen: boolean;
+ setIsOpen: (value:boolean) => void;
+
+}
+
+
+export const useModalState = create((set) => ({
+ isOpen: false,
+ setIsOpen: () =>
+ set((state) => ({ isOpen: !state.isOpen })),
+
+}));
diff --git a/src/zustand/OrderFillter.ts b/src/zustand/OrderFillter.ts
new file mode 100644
index 0000000..6c6e6bf
--- /dev/null
+++ b/src/zustand/OrderFillter.ts
@@ -0,0 +1,50 @@
+import { create } from 'zustand';
+
+interface ModalState {
+ username: string | null;
+ coupon: string | null;
+ state: string | null;
+ fromDate: Date | null;
+ toDate: Date | null;
+ totalFrom: number | null;
+ totalTo: number | null;
+ setUsername: (value: string | null) => void;
+ setCoupon: (value: string | null) => void;
+ setstate: (value: string | null) => void;
+ setFromDate: (value: Date | null) => void;
+ setToDate: (value: Date | null) => void;
+ setTotalFrom: (value: number | null) => void;
+ setTotalTo: (value: number | null) => void;
+ reset: () => void;
+}
+
+export const useOrderFillterState = create((set) => {
+
+ return {
+ username: null,
+ coupon: null,
+ state: null,
+ fromDate: null,
+ toDate: null,
+ totalFrom: null,
+ totalTo: null,
+ setUsername: (value) => set((state) => ({ ...state, username: value })),
+ setCoupon: (value) => set((state) => ({ ...state, coupon: value })),
+ setstate: (value) => set((state) => ({ ...state, state: value })),
+ setFromDate: (value) => set((state) => ({ ...state, fromDate: value })),
+ setToDate: (value) => set((state) => ({ ...state, toDate: value })),
+ setTotalFrom: (value) => set((state) => ({ ...state, totalFrom: value })),
+ setTotalTo: (value) => set((state) => ({ ...state, totalTo: value })),
+ reset: () => {
+ set({
+ username: null,
+ coupon: null,
+ fromDate: null,
+ toDate: null,
+ totalFrom: null,
+ totalTo: null,
+ state:null
+ });
+ },
+ };
+});
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..a273b0c
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx"
+ },
+ "include": [
+ "src"
+ ]
+}