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..ebc5ec0
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,12 @@
+{
+ "cSpell.words": [
+ "aldeen",
+ "antd",
+ "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/index.html b/index.html
new file mode 100644
index 0000000..8168fa3
--- /dev/null
+++ b/index.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+ E-Menu - App
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..d244094
--- /dev/null
+++ b/package.json
@@ -0,0 +1,72 @@
+{
+ "name": "my-app",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@ant-design/icons": "^4.8.3",
+ "@types/node": "^16.18.97",
+ "@types/react": "^18.3.3",
+ "@types/react-dom": "^18.3.0",
+ "antd": "^5.17.4",
+ "apexcharts": "^3.49.1",
+ "axios": "^1.7.2",
+ "bootstrap": "^5.3.3",
+ "chart.js": "^4.4.3",
+ "dayjs": "^1.11.11",
+ "formik": "^2.4.6",
+ "i18next": "^23.11.5",
+ "leaflet": "^1.9.4",
+ "react": "^18.3.1",
+ "react-apexcharts": "^1.4.1",
+ "react-bootstrap": "^2.10.2",
+ "react-bootstrap-sweetalert": "^5.2.0",
+ "react-confirm-alert": "^3.0.6",
+ "react-data-table-component": "^7.6.2",
+ "react-dom": "^18.3.1",
+ "react-i18next": "^13.5.0",
+ "react-icons": "^4.12.0",
+ "react-leaflet": "^4.2.1",
+ "react-number-format": "^5.4.0",
+ "react-player": "^2.16.0",
+ "react-query": "^3.39.3",
+ "react-router-dom": "^6.23.1",
+ "react-select": "^5.8.0",
+ "react-tabs": "^6.0.2",
+ "react-toastify": "^9.1.3",
+ "reactstrap": "^9.2.2",
+ "sass": "^1.77.4",
+ "typescript": "^4.9.5",
+ "web-vitals": "^2.1.4",
+ "xlsx": "^0.18.5",
+ "yup": "^1.4.0",
+ "zustand": "^4.5.2"
+ },
+ "scripts": {
+ "start": "vite",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "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/Layout/images.png b/public/Layout/images.png
new file mode 100644
index 0000000..a283724
Binary files /dev/null and b/public/Layout/images.png differ
diff --git a/public/Logo.png b/public/Logo.png
new file mode 100644
index 0000000..56736b1
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/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..cce85cc
--- /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/statemangment/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..f12aa9d
--- /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/statemangment/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: blockvalue });
+ }
+ };
+
+ 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..ace3d1d
--- /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/statemangment/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 && enterCodesvalue) {
+ Mutation.mutate({ type, id: objectID, value: enterCodesvalue });
+ }
+ };
+
+ 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..41cd9f3
--- /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/statemangment/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..85a8e3c
--- /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/statemangment/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..53a29d4
--- /dev/null
+++ b/src/Components/ValidationField/Ui/KarimSpinner.tsx
@@ -0,0 +1,24 @@
+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..9dc4900
--- /dev/null
+++ b/src/Components/ValidationField/Ui/SearchBar.scss
@@ -0,0 +1,37 @@
+.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: 0.4;
+ }
+
+ .icon {
+ position: absolute;
+ left: 1rem;
+ fill: var(--subtext);
+ width: 1rem;
+ height: 1rem;
+ }
+}
diff --git a/src/Components/ValidationField/Ui/SearchBar.tsx b/src/Components/ValidationField/Ui/SearchBar.tsx
new file mode 100644
index 0000000..46d2566
--- /dev/null
+++ b/src/Components/ValidationField/Ui/SearchBar.tsx
@@ -0,0 +1,45 @@
+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}`, { replace: true });
+ };
+
+ return (
+
+ );
+};
+
+export default SearchBar;
diff --git a/src/Components/ValidationField/ValidationField.tsx b/src/Components/ValidationField/ValidationField.tsx
new file mode 100644
index 0000000..7d3cc79
--- /dev/null
+++ b/src/Components/ValidationField/ValidationField.tsx
@@ -0,0 +1,46 @@
+import React from "react";
+import "./utils/ValidationField.scss";
+import {
+ Date,
+ Time,
+ File,
+ DataRange,
+ SelectField,
+ Default,
+ CheckboxField,
+ MaltyFile,
+ SearchField,
+ TextField,
+ DropFile,
+} from "./View";
+import { ValidationFieldProps, ValidationFieldType } from "./utils/types";
+import LocalSearchField from "./View/LocalSearch";
+import NumberFormate from "./View/NumberFormate";
+
+const components: { [key: string]: React.FC } = {
+ Select: SelectField,
+ Search: SearchField,
+ LocalSearch: LocalSearchField,
+ DataRange: DataRange,
+ TextArea: TextField,
+ Date: Date,
+ Time: Time,
+ File: File,
+ DropFile: DropFile,
+ MaltyFile: MaltyFile,
+ Checkbox: CheckboxField,
+ NumberFormate: NumberFormate,
+};
+
+const ValidationField: React.FC = React.memo(
+ ({ type, ...otherProps }) => {
+ const Component = components[type as ValidationFieldType];
+
+ if (!Component) {
+ return ;
+ }
+ return ;
+ },
+);
+
+export default ValidationField;
diff --git a/src/Components/ValidationField/View/CheckboxField.tsx b/src/Components/ValidationField/View/CheckboxField.tsx
new file mode 100644
index 0000000..2550354
--- /dev/null
+++ b/src/Components/ValidationField/View/CheckboxField.tsx
@@ -0,0 +1,40 @@
+import React from "react";
+import useFormField from "../../../Hooks/useFormField";
+import { Checkbox, Form } from "antd";
+
+const CheckboxField = ({
+ name,
+ label,
+ isDisabled,
+ onChange,
+ Group,
+ className,
+ props,
+ no_label,
+ label_icon,
+}: 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;
diff --git a/src/Components/ValidationField/View/DataRange.tsx b/src/Components/ValidationField/View/DataRange.tsx
new file mode 100644
index 0000000..17723a3
--- /dev/null
+++ b/src/Components/ValidationField/View/DataRange.tsx
@@ -0,0 +1,64 @@
+import { Form, DatePicker } from "antd";
+
+import React from "react";
+import useFormField from "../../../Hooks/useFormField";
+import { MdOutlineEdit } from "react-icons/md";
+
+const { RangePicker } = DatePicker;
+
+const DataRange = ({
+ name,
+ label,
+ Format,
+ props,
+ onChange,
+ isDisabled,
+ placeholder,
+ className,
+ no_label,
+ label_icon,
+}: any) => {
+ const { errorMsg, isError, t, formik } = useFormField(name, props);
+ const onCalendarChange = (value: any) => {
+ formik.setFieldValue(name, value);
+ };
+ return (
+
+ {no_label ? (
+
+ ) : label_icon ? (
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default DataRange;
diff --git a/src/Components/ValidationField/View/Date.tsx b/src/Components/ValidationField/View/Date.tsx
new file mode 100644
index 0000000..a285abc
--- /dev/null
+++ b/src/Components/ValidationField/View/Date.tsx
@@ -0,0 +1,69 @@
+import { Form, DatePicker } from "antd";
+import React from "react";
+import useFormField from "../../../Hooks/useFormField";
+import { MdOutlineEdit } from "react-icons/md";
+import dayjs from "dayjs";
+
+const Date = ({
+ name,
+ label,
+ picker = "date",
+ isDisabled,
+ props,
+ onChange,
+ placeholder,
+ className,
+ no_label,
+ label_icon,
+}: any) => {
+ const { errorMsg, isError, t, formik } = useFormField(name, props);
+
+ const FormikValue = formik.values[name];
+ const onCalendarChange = (value: any) => {
+ formik.setFieldValue(name, value);
+ // console.log(value,"value ");
+ };
+
+ const Formater = "YYYY/MM/DD";
+ return (
+
+ {no_label ? (
+
+ ) : label_icon ? (
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+ {/* */}
+
+
+ );
+};
+
+export default Date;
diff --git a/src/Components/ValidationField/View/Default.tsx b/src/Components/ValidationField/View/Default.tsx
new file mode 100644
index 0000000..d14e28a
--- /dev/null
+++ b/src/Components/ValidationField/View/Default.tsx
@@ -0,0 +1,62 @@
+import { Form, Input } from "antd";
+import React from "react";
+import useFormField from "../../../Hooks/useFormField";
+import { MdOutlineEdit } from "react-icons/md";
+import { Field } from "formik";
+
+const Default = ({
+ name,
+ label,
+ placeholder,
+ isDisabled,
+ onChange,
+ type,
+ no_label,
+ label_icon,
+ ...props
+}: any) => {
+ const { errorMsg, isError, t } = useFormField(name, props);
+
+ return (
+
+ {no_label ? (
+
+ ) : label_icon ? (
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default React.memo(Default);
diff --git a/src/Components/ValidationField/View/DropFile.tsx.tsx b/src/Components/ValidationField/View/DropFile.tsx.tsx
new file mode 100644
index 0000000..3a86955
--- /dev/null
+++ b/src/Components/ValidationField/View/DropFile.tsx.tsx
@@ -0,0 +1,93 @@
+import React, { useEffect, useState } from "react";
+import { LoadingOutlined, PlusOutlined } from "@ant-design/icons";
+import { message, Upload } from "antd";
+import type { GetProp, UploadProps } from "antd";
+import useFormField from "../../../Hooks/useFormField";
+import { ImageBaseURL } from "../../../api/config";
+
+type FileType = Parameters>[0];
+
+const DropFile = ({
+ name,
+ label,
+ onChange,
+ isDisabled,
+ placholder,
+ className,
+ props,
+ no_label,
+ label_icon,
+}: any) => {
+ const { formik, t, isError } = useFormField(name, props);
+ let FormikName = formik?.values[name];
+
+ const FormikValue =
+ typeof FormikName === "string"
+ ? ImageBaseURL + FormikName
+ : FormikName instanceof File
+ ? URL.createObjectURL(FormikName)
+ : "";
+
+ const [imageUrl, setImageUrl] = useState(FormikValue ?? "");
+
+ useEffect(() => {
+ setImageUrl(FormikName);
+ }, [FormikName]);
+
+ const getBase64 = (img: FileType, callback: (url: string) => void) => {
+ const reader = new FileReader();
+ reader.addEventListener("load", () => callback(reader.result as string));
+ reader.readAsDataURL(img);
+ };
+
+ const handleChange: UploadProps["onChange"] = (info) => {
+ if (info.file.status === "done") {
+ getBase64(info.file.originFileObj as FileType, (url) => {
+ setImageUrl(url);
+ });
+ }
+ formik.setFieldValue(name, info.file.originFileObj);
+ };
+ const customRequest = async ({ onSuccess }: any) => {
+ onSuccess();
+ };
+ const uploadButton = (
+
+ );
+
+ return (
+
+
+
+ {imageUrl ? (
+
+ ) : (
+ uploadButton
+ )}
+
+
+ );
+};
+
+export default DropFile;
diff --git a/src/Components/ValidationField/View/File.tsx b/src/Components/ValidationField/View/File.tsx
new file mode 100644
index 0000000..de0538d
--- /dev/null
+++ b/src/Components/ValidationField/View/File.tsx
@@ -0,0 +1,80 @@
+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 imageUrl = formik?.values?.[name] ?? null;
+ // console.log(ImageBaseURL + imageUrl);
+
+ const fileList: UploadFile[] = imageUrl
+ ? [
+ typeof imageUrl === "string"
+ ? {
+ uid: "-1",
+ name: "",
+ status: "done",
+ url: ImageBaseURL + imageUrl,
+ thumbUrl: ImageBaseURL + imageUrl,
+ }
+ : {
+ uid: imageUrl.uid || "-1",
+ name: imageUrl.name || "",
+ status: "done",
+ originFileObj: imageUrl,
+ },
+ ]
+ : [];
+ // console.log(1);
+
+ const FilehandleChange = (value: any) => {
+ // console.log(value,"filevalue");
+ if (value.fileList.length === 0) {
+ formik.setFieldValue(name, null);
+ } else {
+ formik.setFieldValue(name, value?.file?.originFileObj);
+ }
+ };
+ const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
+ onSuccess();
+ };
+ return (
+
+
+
+
+ }
+ >
+ {placholder ?? t("Click_to_upload_the_image")}
+
+ {isError ? "required" : ""}
+
+
+ );
+};
+
+export default File;
diff --git a/src/Components/ValidationField/View/LocalSearch.tsx b/src/Components/ValidationField/View/LocalSearch.tsx
new file mode 100644
index 0000000..382f570
--- /dev/null
+++ b/src/Components/ValidationField/View/LocalSearch.tsx
@@ -0,0 +1,93 @@
+import { Form, Select } from "antd";
+import React, { useState } from "react";
+import useFormField from "../../../Hooks/useFormField";
+import { MdOutlineEdit } from "react-icons/md";
+import { translateOptions } from "../utils/translatedOptions";
+
+const LocalSelectField = ({
+ name,
+ label,
+ placeholder,
+ isDisabled,
+ option,
+ isMulti,
+ onChange,
+ className,
+ props,
+ no_label,
+ label_icon,
+}: any) => {
+ const { errorMsg, isError, t, formik } = useFormField(name, props);
+
+ // State to manage the search input value
+ const [searchValue, setSearchValue] = useState("");
+
+ const handleSearch = (
+ input: string,
+ option: { value: string; label: React.ReactNode | undefined },
+ ) =>
+ option?.label?.toString().toLowerCase().includes(toLowerCase()) ||
+ option?.value?.toString().toLowerCase().includes(toLowerCase());
+
+ const SelectableChange = (value: {
+ value: string;
+ label: React.ReactNode;
+ }) => {
+ formik.setFieldValue(name, value);
+ };
+
+ const handleSelectChange = (value: any) => {
+ formik.setFieldValue(name, value);
+ if (onChange) onChange(value);
+ };
+
+ const handleSearchChange = (input: string) => {
+ setSearchValue(input); // Update the search input value
+ };
+
+ return (
+
+ {no_label ? (
+
+ ) : label_icon ? (
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+ );
+};
+
+export default React.memo(LocalSelectField);
diff --git a/src/Components/ValidationField/View/MaltyFile.tsx b/src/Components/ValidationField/View/MaltyFile.tsx
new file mode 100644
index 0000000..f18ad30
--- /dev/null
+++ b/src/Components/ValidationField/View/MaltyFile.tsx
@@ -0,0 +1,85 @@
+import { Button, Upload } from "antd";
+import { UploadOutlined } from "@ant-design/icons";
+
+import useFormField from "../../../Hooks/useFormField";
+
+const MaltyFile = ({
+ name,
+ label,
+ onChange,
+ isDisabled,
+ placeholder,
+ className,
+ props,
+}: any) => {
+ const { formik, t, isError } = useFormField(name, props);
+ let imageUrl = formik?.values?.[name] ?? null;
+
+ // Mapping formik values to fileList format
+ const fileList = imageUrl
+ ? imageUrl.map((file: any, index: number) => {
+ // console.log(file,"file");
+
+ return file instanceof File
+ ? {
+ uid: index,
+ name: file?.name,
+ status: "done",
+ originFileObj: file,
+ }
+ : {
+ uid: index,
+ id: file?.id,
+ name: file?.name,
+ status: "done",
+ url: file?.url || "",
+ thumbUrl: file?.url || "",
+ };
+ })
+ : [];
+
+ const FilehandleChange = ({ fileList }: any) => {
+ if (fileList.length === 0) {
+ formik.setFieldValue(name, null);
+ } else {
+ formik.setFieldValue(
+ name,
+ fileList.map((file: any) => file?.originFileObj ?? file),
+ );
+ }
+ };
+ // Custom request function
+ const customRequest = async ({ onSuccess }: any) => {
+ // Perform any necessary actions before onSuccess is called
+ onSuccess();
+ };
+
+ return (
+
+
+
+
+ }
+
+ >
+ {t(placeholder ?? t("upload_image") )}
+
+ {isError ? "required" : ""}
+
+
+ );
+};
+
+export default MaltyFile;
diff --git a/src/Components/ValidationField/View/NumberFormate.tsx b/src/Components/ValidationField/View/NumberFormate.tsx
new file mode 100644
index 0000000..ca50a4b
--- /dev/null
+++ b/src/Components/ValidationField/View/NumberFormate.tsx
@@ -0,0 +1,75 @@
+import { Form, Input, InputNumber } from "antd";
+import React from "react";
+import useFormField from "../../../Hooks/useFormField";
+import { MdOutlineEdit } from "react-icons/md";
+import { Field } from "formik";
+
+const NumberFormate = ({
+ name,
+ label,
+ placeholder,
+ isDisabled,
+ props,
+ type,
+ no_label,
+ label_icon,
+}: any) => {
+ const { errorMsg, isError, t, formik } = useFormField(name, props);
+ const SelectableChange = (value: {
+ value: string;
+ label: React.ReactNode;
+ }) => {
+ formik.setFieldValue(name, value);
+ };
+ return (
+
+ {no_label ? (
+
+ ) : label_icon ? (
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+ `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",")
+ }
+ parser={(value: any) =>
+ value?.replace(/\$\s?|(,*)/g, "") as unknown as number
+ }
+ min="0"
+ type={type ?? "text"}
+ value={formik.values[name]}
+ onChange={SelectableChange}
+ placeholder={t(
+ `${placeholder ? placeholder : label ? label : name}`,
+ )}
+ name={name}
+ disabled={isDisabled}
+ size="large"
+
+
+ // onChange={onChange ? onChange : handleChange}
+ />
+
+
+ );
+};
+
+export default React.memo(NumberFormate);
diff --git a/src/Components/ValidationField/View/SearchField.tsx b/src/Components/ValidationField/View/SearchField.tsx
new file mode 100644
index 0000000..ff35a45
--- /dev/null
+++ b/src/Components/ValidationField/View/SearchField.tsx
@@ -0,0 +1,87 @@
+import { Form, Select } from "antd";
+import React, { useEffect, useState } from "react";
+import useFormField from "../../../Hooks/useFormField";
+import { useNavigate } from "react-router-dom";
+import { MdOutlineEdit } from "react-icons/md";
+
+const SearchField = ({
+ name,
+ label,
+ placeholder,
+ isDisabled,
+ searchBy,
+ option,
+ isMulti,
+ onChange,
+ className,
+ props,
+ no_label,
+ label_icon,
+}: any) => {
+ const { errorMsg, isError, t, formik } = useFormField(name, props);
+ const [searchQuery, setSearchQuery] = useState("");
+ const navigate = useNavigate();
+ useEffect(() => {
+ const searchParams = new URLSearchParams(window?.location?.search);
+ setSearchQuery(searchParams?.get("search") || "");
+ }, []);
+
+ const SelectableChange = (value: {
+ value: string;
+ label: React.ReactNode;
+ }) => {
+ formik?.setFieldValue(name, value);
+ };
+ const SearchHandleChange = (value: any) => {
+ navigate(`${window?.location?.pathname}?${searchBy}=${value}`, {
+ replace: true,
+ });
+ };
+
+ return (
+
+ {no_label ? (
+
+ ) : label_icon ? (
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+
+ );
+};
+
+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..880a9ed
--- /dev/null
+++ b/src/Components/ValidationField/View/SelectField.tsx
@@ -0,0 +1,72 @@
+import { Form, Select } from "antd";
+import React from "react";
+import useFormField from "../../../Hooks/useFormField";
+import { MdOutlineEdit } from "react-icons/md";
+import { translateOptions } from "../utils/translatedOptions";
+
+const SelectField = ({
+ name,
+ label,
+ placeholder,
+ isDisabled,
+ option,
+ isMulti,
+ onChange,
+ className,
+ props,
+ no_label,
+ label_icon,
+}: any) => {
+ const { errorMsg, isError, t, formik } = useFormField(name, props);
+ const SelectableChange = (value: {
+ value: string;
+ label: React.ReactNode;
+ }) => {
+ formik.setFieldValue(name, value);
+ };
+ // console.log(name,"Select");
+
+ return (
+
+ {no_label ? (
+
+ ) : label_icon ? (
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default React.memo(SelectField);
diff --git a/src/Components/ValidationField/View/TextAreaField.tsx b/src/Components/ValidationField/View/TextAreaField.tsx
new file mode 100644
index 0000000..455e056
--- /dev/null
+++ b/src/Components/ValidationField/View/TextAreaField.tsx
@@ -0,0 +1,50 @@
+import { Form, Input } from "antd";
+import React from "react";
+import useFormField from "../../../Hooks/useFormField";
+import { Field } from "formik";
+const { TextArea } = Input;
+
+const TextAreaField = ({
+ name,
+ label,
+ placeholder,
+ isDisabled,
+ onChange,
+ props,
+ type,
+}: any) => {
+ const { 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/TextField.tsx b/src/Components/ValidationField/View/TextField.tsx
new file mode 100644
index 0000000..ae71b55
--- /dev/null
+++ b/src/Components/ValidationField/View/TextField.tsx
@@ -0,0 +1,65 @@
+import { Form, Input } from "antd";
+import React from "react";
+import useFormField from "../../../Hooks/useFormField";
+import { MdOutlineEdit } from "react-icons/md";
+import { Field } from "formik";
+const { TextArea } = Input;
+
+const TextField = ({
+ name,
+ label,
+ placeholder,
+ isDisabled,
+ onChange,
+ props,
+ no_label,
+ label_icon,
+}: any) => {
+ const { formik, isError, errorMsg, t } = useFormField(name, props);
+ const TextFieldhandleChange = (
+ e: React.ChangeEvent,
+ ) => {
+ // console.log('Change:', e.target.value);
+ formik.setFieldValue(name, e.target.value);
+ };
+ return (
+
+ {no_label ? (
+
+ ) : label_icon ? (
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default React.memo(TextField);
diff --git a/src/Components/ValidationField/View/Time.tsx b/src/Components/ValidationField/View/Time.tsx
new file mode 100644
index 0000000..1847c0f
--- /dev/null
+++ b/src/Components/ValidationField/View/Time.tsx
@@ -0,0 +1,68 @@
+import { Form, TimePicker } from "antd";
+import React from "react";
+import useFormField from "../../../Hooks/useFormField";
+import { MdOutlineEdit } from "react-icons/md";
+import dayjs from "dayjs";
+
+const Time = ({
+ name,
+ label,
+ className,
+ isDisabled,
+ onChange,
+ props,
+ placeholder,
+ no_label,
+ label_icon,
+}: any) => {
+ const { errorMsg, isError, t, formik } = useFormField(name, props);
+ const onCalendarChange = (value: any) => {
+ formik.setFieldValue(name, value);
+ };
+
+ const Formater = "H:mm";
+ const FormikValue = formik.values[name];
+
+ return (
+
+ {no_label ? (
+
+ ) : label_icon ? (
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default Time;
diff --git a/src/Components/ValidationField/View/index.tsx b/src/Components/ValidationField/View/index.tsx
new file mode 100644
index 0000000..0403969
--- /dev/null
+++ b/src/Components/ValidationField/View/index.tsx
@@ -0,0 +1,25 @@
+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 MaltyFile from "./MaltyFile";
+import SearchField from "./SearchField";
+import TextField from "./TextField";
+import DropFile from "./DropFile.tsx";
+
+export {
+ Time,
+ SelectField,
+ Date,
+ DataRange,
+ CheckboxField,
+ Default,
+ File,
+ MaltyFile,
+ SearchField,
+ TextField,
+ DropFile,
+};
diff --git a/src/Components/ValidationField/index.tsx b/src/Components/ValidationField/index.tsx
new file mode 100644
index 0000000..20e711f
--- /dev/null
+++ b/src/Components/ValidationField/index.tsx
@@ -0,0 +1,16 @@
+import { useState } from "react";
+import { ErrorMessage, useField, Field, useFormikContext } from "formik";
+import { useTranslation } from "react-i18next";
+import { FaExclamationCircle } from "react-icons/fa";
+import { convert_data_to_select } from "../../Layout/app/Const";
+
+export {
+ useState,
+ ErrorMessage,
+ useField,
+ Field,
+ useFormikContext,
+ useTranslation,
+ FaExclamationCircle,
+ convert_data_to_select,
+};
diff --git a/src/Components/ValidationField/utils/ValidationField.scss b/src/Components/ValidationField/utils/ValidationField.scss
new file mode 100644
index 0000000..ed6599e
--- /dev/null
+++ b/src/Components/ValidationField/utils/ValidationField.scss
@@ -0,0 +1,200 @@
+.LabelWithIcon {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+}
+.ValidationField {
+ margin-bottom: 1.3vw;
+ position: relative;
+ > * {
+ width: 100%;
+ }
+ .text,
+ .ant-form-item {
+ margin-bottom: 7px !important;
+ > span {
+ color: transparent;
+ }
+ }
+
+ // .ant-select-outlined:not(.ant-select-customize-input) .ant-select-selector {
+ // border: 1px solid var(--border-color);
+ // }
+
+ .Select_error {
+ .ant-select-selector {
+ border: 1px solid red !important;
+ }
+ }
+
+ // .ValidationField{
+ // .ant-select-selector{
+ // border: 1px solid var(--border-color) ;
+
+ // }
+ // }
+ > 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);
+ margin-bottom: 15px;
+ font-weight: bold;
+}
+
+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 */
+// }
+// .upload_image_button {
+// .ant-btn {
+// min-height: 3vw !important;
+// border: 0.1vw solid var(--border-color);
+
+// display: flex;
+// align-items: center;
+// justify-content: center;
+// }
+// }
+// .ant-select-outlined:not(.ant-select-customize-input) .ant-select-selector {
+// min-height: 3vw !important;
+// }
+// .ant-select-multiple.ant-select-lg .ant-select-selection-overflow {
+// min-height: 3vw !important;
+// }
+
+// .ant-upload-list .ant-upload-list-item {
+// // height:3vw !important;
+// border: 1px solid var(--border-color) !important;
+// }
+
+// .TowValidationItems {
+// display: flex;
+// gap: 3%;
+// > label {
+// display: none;
+// }
+// }
+
+// .ant-select .ant-select-arrow {
+// inset-inline-end: 1vw;
+// }
+// .ant-input-affix-wrapper-lg {
+// padding: 0.5vw 1vw;
+// font-size: 1vw;
+// min-height: 3vw;
+// border-radius: 0.6vw;
+// }
+
+// .ant-picker-outlined {
+// padding: 0.5vw 1vw;
+// font-size: 1vw;
+// min-height: 3vw;
+// border-radius: 0.6vw;
+// border: 1px solid var(--border-color);
+// }
+
+// .ant-select-single.ant-select-lg .ant-select-selector {
+// min-height: 3vw;
+// border-radius: 0.6vw;
+// }
+// .ant-select-single .ant-select-selector .ant-select-selection-search-input {
+// min-height: 3vw;
+// }
+
+// .ant-select-outlined .ant-select-selector {
+// min-height: 3vw !important;
+// border-radius: 0.6vw !important;
+// }
+// .ant-select-single.ant-select-lg {
+// min-height: 3vw;
+// }
+
+// .ant-upload-wrapper .ant-upload-list .ant-upload-list-item {
+// width: 21.5vw;
+// }
+
+// .ant-input-number-outlined {
+// width: 100%;
+// height: 3vw;
+// }
+// .ant-input-number-lg ant-input-number-input {
+// width: 100%;
+// height: 3vw;
+// }
+
+// .bigRow {
+// width: 100%;
+// display: flex;
+// justify-content: space-between;
+// flex-wrap: wrap;
+// > *.w-100 {
+// width: 48% !important;
+// }
+// }
+
+// .ant-input-number-affix-wrapper-lg {
+// width: 100%;
+// height: 3vw;
+// border-radius: 0.6vw;
+// border: 1px solid var(--border-color);
+// }
+
+// .TwoSelectGroup {
+// display: flex;
+// gap: 10px;
+// margin-bottom: 20px;
+// }
+// .TwoSelectGroupbutton {
+// margin-bottom: 20px;
+// }
diff --git a/src/Components/ValidationField/utils/ValidationState.ts b/src/Components/ValidationField/utils/ValidationState.ts
new file mode 100644
index 0000000..4af51fe
--- /dev/null
+++ b/src/Components/ValidationField/utils/ValidationState.ts
@@ -0,0 +1,11 @@
+import { create } from "zustand";
+
+interface ValidationState {
+ Validation: any[];
+ setValidation: (value: any[]) => void;
+}
+
+export const useValidationState = create((set) => ({
+ Validation: [],
+ setValidation: (value) => set((state) => ({ Validation: value })),
+}));
diff --git a/src/Components/ValidationField/utils/translatedOptions.ts b/src/Components/ValidationField/utils/translatedOptions.ts
new file mode 100644
index 0000000..eda92a2
--- /dev/null
+++ b/src/Components/ValidationField/utils/translatedOptions.ts
@@ -0,0 +1,6 @@
+export const translateOptions = (options: any, t: any) => {
+ return options.map((opt: any) => ({
+ ...opt,
+ label: t(`${opt.label}`),
+ }));
+};
diff --git a/src/Components/ValidationField/utils/types.ts b/src/Components/ValidationField/utils/types.ts
new file mode 100644
index 0000000..0959f66
--- /dev/null
+++ b/src/Components/ValidationField/utils/types.ts
@@ -0,0 +1,171 @@
+export type ValidationFieldType =
+ | "text"
+ | "Select"
+ | "LocalSearch"
+ | "Search"
+ | "DataRange"
+ | "Date"
+ | "Time"
+ | "File"
+ | "MaltyFile"
+ | "DropFile"
+ | "Checkbox"
+ | "number"
+ | "password"
+ | "email"
+ | "TextArea";
+
+export interface ValidationFieldPropsText {
+ name: string;
+ no_label?: boolean;
+ label_icon?: boolean;
+ type: "text";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?: "ltr" | "rtl";
+}
+
+export interface ValidationFieldPropsSelect {
+ name: string;
+ no_label?: boolean;
+ label_icon?: boolean;
+ type: "Select";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: any;
+ dir?: "ltr" | "rtl";
+ option: any[];
+ isMulti?: boolean;
+}
+
+export interface ValidationFieldPropsLocalSearch {
+ name: string;
+ no_label?: boolean;
+ label_icon?: boolean;
+ type: "LocalSearch";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?: "ltr" | "rtl";
+ option: any[];
+ isMulti?: boolean;
+}
+export interface ValidationFieldPropsSearch {
+ name: string;
+ no_label?: boolean;
+ label_icon?: boolean;
+ type: "Search";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?: "ltr" | "rtl";
+ option: any[];
+ isMulti?: boolean;
+ searchBy: string;
+}
+export interface ValidationFieldPropsDataRange {
+ name: string;
+ no_label?: boolean;
+ label_icon?: boolean;
+ 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;
+ no_label?: boolean;
+ label_icon?: boolean;
+ type: "Date";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?: "ltr" | "rtl";
+ picker?: "data" | "week" | "month" | "quarter" | "year";
+}
+
+export interface ValidationFieldPropsTime {
+ name: string;
+ no_label?: boolean;
+ label_icon?: boolean;
+ type: "Time";
+ label?: string;
+ placeholder?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?: "ltr" | "rtl";
+}
+
+export interface ValidationFieldPropsFile {
+ name: string;
+ no_label?: boolean;
+ label_icon?: boolean;
+ type: "File" | "MaltyFile" | "DropFile";
+ acceptedFileType?:string;
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?: "ltr" | "rtl";
+}
+export interface ValidationFieldPropsCheckbox {
+ name: string;
+ no_label?: boolean;
+ label_icon?: boolean;
+ type: "Checkbox";
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?: "ltr" | "rtl";
+ Group?: boolean;
+}
+export interface ValidationFieldPropstext {
+ name: string;
+ no_label?: boolean;
+ label_icon?: boolean;
+ type?:
+ | "text"
+ | "number"
+ | "password"
+ | "email"
+ | "TextArea"
+ | "NumberFormate";
+ label?: string;
+ className?: string;
+ placeholder?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?: "ltr" | "rtl";
+ Group?: boolean;
+ [key: string]: any; // Index signature to allow any additional props
+}
+
+export type ValidationFieldProps =
+ | ValidationFieldPropsText
+ | ValidationFieldPropsSelect
+ | ValidationFieldPropsLocalSearch
+ | 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/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..e44636c
--- /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..3ed64d3
--- /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/statemangment/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..67910e3
--- /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/statemangment/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..4d67dfd
--- /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/statemangment/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..85a61b4
--- /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/statemangment/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,setObjectToEdit} = usePageState()
+ const {t} = useTranslation();
+ const navigate = useNavigate();
+ // console.log(BarStatus);
+
+ const navigateToParent = () => {
+ navigate(-1)
+ if(objectToEdit){
+ setObjectToEdit([])
+ }
+ };
+
+ 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..eb8a483
--- /dev/null
+++ b/src/Layout/Dashboard/useCloseModal.ts
@@ -0,0 +1,18 @@
+import React, { useEffect } from 'react'
+import { usePageState } from '../../lib/statemangment/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..f193733
--- /dev/null
+++ b/src/Layout/app/Const.tsx
@@ -0,0 +1,47 @@
+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 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..17b9ff4
--- /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/statemangment/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..2f3e409
--- /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/statemangment/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..828e387
--- /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/statemangment/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..a048f32
--- /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/statemangment/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..7765a9f
--- /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/statemangment/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..92081e6
--- /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..7f58b6c
--- /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..8cd4532
--- /dev/null
+++ b/src/Pages/Categories/View/EditPage.tsx
@@ -0,0 +1,78 @@
+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/statemangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetCategories, useUpdateCategories } from '../../../api/Categories';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+import { useParams } from 'react-router-dom';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const {id} = useParams()
+ const { data,isRefetching } = useGetCategories({
+ show:id
+ })
+ const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateCategories()
+ 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/Home/Page.tsx b/src/Pages/Home/Page.tsx
new file mode 100644
index 0000000..89830ea
--- /dev/null
+++ b/src/Pages/Home/Page.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+
+const Page = () => {
+
+ return (
+ Page
+ )
+}
+
+export default Page
\ No newline at end of file
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..5ddc3ff
--- /dev/null
+++ b/src/Pages/Meal/View/EditPage.tsx
@@ -0,0 +1,87 @@
+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/statemangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetMeal, useUpdateMeal } from '../../../api/Meal';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+import { useParams } from 'react-router-dom';
+import { isItArrayOfString } from '../../../utils/Array/isItArrayOfString';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const {id} = useParams()
+ const { data,isRefetching } = useGetMeal({
+ show:id
+ })
+ const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateMeal()
+
+
+
+ const handleSubmit = (values: any) => {
+ const data_to_send = {...values}
+
+ if( typeof values?.video === "string" ){
+ delete data_to_send["video"]
+ }
+ if(isItArrayOfString(values?.images)){
+ delete data_to_send["images"]
+ }
+
+ mutate(data_to_send);
+}
+
+
+ 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..99375d6
--- /dev/null
+++ b/src/Pages/Offer/View/EditPage.tsx
@@ -0,0 +1,77 @@
+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/statemangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetOffer, useUpdateOffer } from '../../../api/Offer';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+import { useParams } from 'react-router-dom';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const {id} = useParams()
+ const { data,isRefetching } = useGetOffer({
+ show:id
+ })
+ const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateOffer()
+ 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/Restaurant/Page.tsx b/src/Pages/Restaurant/Page.tsx
new file mode 100644
index 0000000..2267d67
--- /dev/null
+++ b/src/Pages/Restaurant/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 { useGetRestaurant } from '../../api/Restaurant'
+import SearchField from '../../Layout/Dashboard/SearchField'
+
+function Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGetRestaurant()
+
+ const navigate = useNavigate()
+ const totalRows = data?.meta?.total;
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Page
+
diff --git a/src/Pages/Restaurant/View/AddForm.tsx b/src/Pages/Restaurant/View/AddForm.tsx
new file mode 100644
index 0000000..6a090a4
--- /dev/null
+++ b/src/Pages/Restaurant/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/Restaurant/View/AddPage.tsx b/src/Pages/Restaurant/View/AddPage.tsx
new file mode 100644
index 0000000..4ad0dbf
--- /dev/null
+++ b/src/Pages/Restaurant/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 { useAddRestaurant } from '../../../api/Restaurant';
+import Form from './AddForm';
+
+const AddRestaurantPage = () => {
+
+
+ const { mutate, isLoading:IsloadingButton, isSuccess } = useAddRestaurant()
+ const handleSubmit = (values: any) => {
+ mutate(values);
+ };
+
+
+ const { t } = useTranslation();
+
+ useNavigateOnSuccess(isSuccess, '/Restaurant')
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, handleSubmit,IsloadingButton };
+
+
+ return (
+
+
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default AddRestaurantPage
\ No newline at end of file
diff --git a/src/Pages/Restaurant/View/EditForm.tsx b/src/Pages/Restaurant/View/EditForm.tsx
new file mode 100644
index 0000000..7f58b6c
--- /dev/null
+++ b/src/Pages/Restaurant/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/Restaurant/View/EditPage.tsx b/src/Pages/Restaurant/View/EditPage.tsx
new file mode 100644
index 0000000..f80e9f2
--- /dev/null
+++ b/src/Pages/Restaurant/View/EditPage.tsx
@@ -0,0 +1,78 @@
+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/statemangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetRestaurant, useUpdateRestaurant } from '../../../api/Restaurant';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+import { useParams } from 'react-router-dom';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const {id} = useParams()
+ const { data,isRefetching } = useGetRestaurant({
+ show:id
+ })
+ const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateRestaurant()
+ const handleSubmit = (values: any) => {
+ if( typeof values?.image === "string" ){
+ delete values["image"]
+ }
+
+ mutate({...values, _method : "put"});
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/Restaurant')
+
+
+ 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/Restaurant/formUtil.ts b/src/Pages/Restaurant/formUtil.ts
new file mode 100644
index 0000000..2510793
--- /dev/null
+++ b/src/Pages/Restaurant/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/Restaurant/useTableColumns.tsx b/src/Pages/Restaurant/useTableColumns.tsx
new file mode 100644
index 0000000..8b70665
--- /dev/null
+++ b/src/Pages/Restaurant/useTableColumns.tsx
@@ -0,0 +1,73 @@
+
+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 { useDeleteRestaurant } from "../../api/Restaurant";
+import { useModalState } from "../../zustand/Modal";
+
+function fnDelete(props :any ){}
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+ const deleteMutation = useDeleteRestaurant()
+ 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("image"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => {
+ let str = row?.image;
+ return
+ }
+
+ },
+
+ {
+ name: t("name"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.name
+ },
+
+ {
+ name: t("address"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.address
+ },
+
+ {
+ 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/Groups/FieldGroup.tsx b/src/Pages/Setting/Groups/FieldGroup.tsx
new file mode 100644
index 0000000..76a0760
--- /dev/null
+++ b/src/Pages/Setting/Groups/FieldGroup.tsx
@@ -0,0 +1,96 @@
+import React from "react";
+import { Input, Button } from "antd";
+import { useFormikContext } from "formik";
+import { useTranslation } from "react-i18next";
+
+interface FieldGroupProps {
+ array_name: string;
+ title:string;
+ static?: boolean;
+ only_value?: boolean;
+}
+
+const FieldGroup: React.FC = ({ array_name ,title,static:isStatic,only_value}) => {
+ const { values, setFieldValue } = useFormikContext();
+ const addFieldGroup = () => {
+ setFieldValue(array_name, [
+ ...(values?.[array_name] || []),
+ { key: null, value: null },
+ ]);
+ };
+ const deleteFieldGroup = () => {
+ const updatedArray = values?.[array_name]?.slice(0, -1) || [];
+ setFieldValue(array_name, updatedArray);
+ };
+
+
+ const handleChangeKey = (
+ e: React.ChangeEvent,
+ index: number
+ ) => {
+ const Selects = values?.[array_name] ?? [];
+ Selects[index].key = e.target.value;
+ setFieldValue(array_name, Selects);
+ };
+
+ const handleChangeValue = (
+ e: React.ChangeEvent,
+ index: number
+ ) => {
+ const Selects = values?.[array_name] ?? [];
+ Selects[index].value = e.target.value;
+ setFieldValue(array_name, Selects);
+ };
+
+ const selectsArray = values?.[array_name] ?? [];
+ const { t } = useTranslation();
+
+ return (
+ <>
+
+ {selectsArray.map((group: { key: string; value: string }, index: number) => (
+
+ handleChangeKey(e, index)}
+ value={group.key}
+ size="large"
+ style={{ width: "100%" }}
+ allowClear
+ disabled={only_value}
+ />
+ handleChangeValue(e, index)}
+ value={group.value}
+ size="large"
+ style={{ width: "100%" }}
+ allowClear
+
+ />
+
+ ))}
+ {!isStatic &&
+
+
+
+
+ }
+
+ >
+ );
+};
+
+export default FieldGroup;
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..51de6c1
--- /dev/null
+++ b/src/Pages/Setting/Page.tsx
@@ -0,0 +1,98 @@
+import { Image, Spin } from "antd";
+import React from "react";
+import SimpleMap from "./Map";
+import { useGetSetting } from "../../api/GuestApi";
+import { TOKEN_KEY } from "../../api/config";
+import useAuthState from "../../lib/statemangment/AuthState";
+import ReactPlayer from 'react-player'
+import { FaEdit } from "react-icons/fa";
+import { useNavigate } from "react-router-dom";
+
+const Page = () => {
+ 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 ?? [];
+ const fakeIMage = [1,1,1,1,1,1]
+ const handel_navigate = (id:number)=>{
+ console.log(id);
+
+
+ navigate(`/Setting/${id}`)
+ }
+ 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 &&
+
+
+ }
+
+
+ handel_navigate(id)} size={30}/>
+
+
+ );
+};
+
+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..637410b
--- /dev/null
+++ b/src/Pages/Setting/View/EditForm.tsx
@@ -0,0 +1,46 @@
+
+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';
+import FieldGroup from '../Groups/FieldGroup';
+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..d890444
--- /dev/null
+++ b/src/Pages/Setting/View/EditPage.tsx
@@ -0,0 +1,90 @@
+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/statemangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetSetting, useUpdateSetting } from '../../../api/setting';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+import { useParams } from 'react-router-dom';
+import { convertArrayToJsonString } from '../../../utils/Array/convertArrayToJsonString';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const {id} = useParams()
+
+ const { data,isRefetching } = useGetSetting({
+ show:id
+ })
+ const { mutate, isSuccess,isLoading:IsloadingButton } = useUpdateSetting()
+
+ const handleSubmit = (values:any) => {
+ const dataToSend = {...values};
+
+ const slogan = convertArrayToJsonString(values?.slogan);
+ const phone_number = values?.phone_number;
+ const email = values?.email;
+ const contact_info = convertArrayToJsonString([{key: 'phone_number', value:phone_number},{key: 'email', value:email}])
+
+ dataToSend["slogan"] = slogan;
+ dataToSend["contact_info"] = contact_info;
+
+
+ // mutate({...values, _method : "put"});
+ console.log(dataToSend,"dataToSend");
+
+
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/Setting')
+
+
+ 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..b1e2709
--- /dev/null
+++ b/src/Pages/Setting/formUtil.ts
@@ -0,0 +1,37 @@
+
+import * as Yup from "yup";
+import { KeyAndValue, objectToArray } from "../../utils/object/objectToArray";
+import { Restaurant } from "../../types/item";
+
+
+export const getInitialValues = (objectToEdit: Restaurant ): any => {
+
+
+ const slogan: KeyAndValue[] = objectToArray(objectToEdit?.slogan);
+ const contact_info: KeyAndValue[] = objectToArray(objectToEdit?.contact_info);
+ const categories = objectToEdit?.categories?.map((item:any)=>(item.id)) || null;
+
+ return {
+ id: objectToEdit?.id ?? null,
+ name: objectToEdit?.name ?? null,
+ images: objectToEdit?.images ?? null,
+ logo: objectToEdit?.logo ?? null,
+
+ address: objectToEdit?.address ?? null,
+ phone_number:contact_info?.[0]?.value ?? null,
+ email:contact_info?.[1]?.value ?? null,
+ categories:categories,
+ slogan: 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..8deda4c
--- /dev/null
+++ b/src/ProviderContainer.tsx
@@ -0,0 +1,22 @@
+import React, { ReactNode } from 'react'
+import QueryProvider from './lib/ReactQueryProvider'
+import { BrowserRouter } from 'react-router-dom'
+import ToastProvider from './lib/ToastProvider'
+
+type ProviderContainerProps = {
+ children:ReactNode
+
+}
+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..8e1e7e2
--- /dev/null
+++ b/src/Routes.tsx
@@ -0,0 +1,147 @@
+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 RestaurantPage from "./Pages/Restaurant/Page";
+import AddRestaurantPage from "./Pages/Restaurant/View/AddPage";
+import EditRestaurant from "./Pages/Restaurant/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";
+
+
+import Home from './Pages/Home/Page'
+
+
+
+
+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: ,
+ icon: ,
+ href: "/",
+ },
+
+
+
+
+ {
+ name: "Restaurant",
+ element: ,
+ icon: ,
+ href: "/Restaurant",
+ },
+ {
+ href: "/Restaurant/:id",
+ element: ,
+ hidden:true
+ },
+ {
+ href: "/Restaurant/add",
+ element: ,
+ hidden:true
+ },
+
+
+ {
+ 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..38d9750
--- /dev/null
+++ b/src/Styles/AppStyle/Varibils.scss
@@ -0,0 +1,36 @@
+:root {
+ --primary:black ;
+ --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..df29ed9
--- /dev/null
+++ b/src/api/Categories.ts
@@ -0,0 +1,22 @@
+
+import useGetQuery from "./helper/useGetQuery";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `category`,
+ GET_ALL: `category`,
+ DELETE: `category`,
+ UPDATE: `category`,
+
+};
+const KEY = "categories"
+
+
+export const useGetCategories = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params);
+
+export const useAddCategories = () => useAddMutation(KEY, API.ADD);
+export const useUpdateCategories = (method?:any) => useUpdateMutation(KEY, API.UPDATE);
+
+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..9f10b1a
--- /dev/null
+++ b/src/api/GuestApi.ts
@@ -0,0 +1,22 @@
+
+import useGetQuery from "./helper/useGetQuery";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `guest/restaurant`,
+ GET_ALL: `guest/restaurant`,
+ DELETE: `guest/restaurant`,
+ UPDATE: `guest/restaurant`,
+
+};
+const KEY = "setting"
+
+
+export const useGetSetting = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params);
+
+export const useAddSetting = () => useAddMutation(KEY, API.ADD);
+export const useUpdateSetting = (method?:any) => useUpdateMutation(KEY, API.UPDATE);
+
+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..ac97da0
--- /dev/null
+++ b/src/api/Meal.ts
@@ -0,0 +1,22 @@
+
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetQuery from "./helper/useGetQuery";
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `meal`,
+ GET_ALL: `meal`,
+ DELETE: `meal`,
+ UPDATE: `meal`,
+
+};
+const KEY = "Meal"
+
+
+export const useGetMeal = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params,option);
+
+export const useAddMeal = () => useAddMutation(KEY, API.ADD);
+export const useUpdateMeal = () => useUpdateMutation(KEY, API.UPDATE);
+
+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..f159365
--- /dev/null
+++ b/src/api/Offer.ts
@@ -0,0 +1,22 @@
+
+import useGetQuery from "./helper/useGetQuery";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `offer`,
+ GET_ALL: `offer`,
+ DELETE: `offer`,
+ UPDATE: `offer`,
+
+};
+const KEY = "Offer"
+
+
+export const useGetOffer = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params);
+
+export const useAddOffer = () => useAddMutation(KEY, API.ADD);
+export const useUpdateOffer = (method?:any) => useUpdateMutation(KEY, API.UPDATE);
+
+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..3e7413f
--- /dev/null
+++ b/src/api/Restaurant.ts
@@ -0,0 +1,22 @@
+
+import useGetQuery from "./helper/useGetQuery";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `restaurant`,
+ GET_ALL: `restaurant`,
+ DELETE: `restaurant`,
+ UPDATE: `restaurant`,
+
+};
+const KEY = "Restaurant"
+
+
+export const useGetRestaurant = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params);
+
+export const useAddRestaurant = () => useAddMutation(KEY, API.ADD);
+export const useUpdateRestaurant = (method?:any) => useUpdateMutation(KEY, API.UPDATE);
+
+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..8b71874
--- /dev/null
+++ b/src/api/config.ts
@@ -0,0 +1,19 @@
+
+// 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"
+
+
+export const HEADER_KEY = "X-Custom-Query-Key";
diff --git a/src/api/helper/AxiosBuilder.ts b/src/api/helper/AxiosBuilder.ts
new file mode 100644
index 0000000..d8cd905
--- /dev/null
+++ b/src/api/helper/AxiosBuilder.ts
@@ -0,0 +1,43 @@
+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/useAddMutation.ts b/src/api/helper/useAddMutation.ts
new file mode 100644
index 0000000..adaccc7
--- /dev/null
+++ b/src/api/helper/useAddMutation.ts
@@ -0,0 +1,29 @@
+import { useMutation, UseMutationResult } from "react-query";
+import useAxios from "./useAxios";
+import { HEADER_KEY } from "../config";
+import { AxiosResponse } from "../../types/Axios";
+
+function useAddMutation(
+ key: string,
+ url: string,
+ message?: string,
+
+): UseMutationResult {
+ const axios = useAxios();
+ return useMutation(
+ async (dataToSend) => {
+
+ const { data } = await axios.post(url, dataToSend, {
+ headers: {
+ "Content-Type": "multipart/form-data",
+ [HEADER_KEY]: key,
+ },
+ });
+ return data;
+
+ },
+
+ );
+}
+
+export default useAddMutation;
diff --git a/src/api/helper/useAxios.ts b/src/api/helper/useAxios.ts
new file mode 100644
index 0000000..d7d2b80
--- /dev/null
+++ b/src/api/helper/useAxios.ts
@@ -0,0 +1,82 @@
+
+import { BaseURL, HEADER_KEY } from "../config";
+import AxiosBuilder from "./AxiosBuilder";
+import { useTranslation } from "react-i18next";
+import { toast } from "react-toastify";
+import { useQueryClient } from "react-query";
+import { useNavigate } from "react-router-dom";
+import useAuthState from "../../lib/statemangment/AuthState";
+import { useValidationState } from "../../Components/ValidationField/utils/ValidationState";
+import { AxiosQueryEnum, AxiosStatusEnum } from "../../enums/Axios";
+import { usePageState } from "../../lib/statemangment/LayoutPagestate";
+
+function useAxios() {
+ const { isAuthenticated, token } = useAuthState();
+
+ const { setValidation } = useValidationState((state) => state);
+ const {setObjectToEdit} = usePageState()
+ const [t] = useTranslation();
+ const queryClient = useQueryClient();
+
+ const { logout } = useAuthState();
+ const navigate = useNavigate();
+
+ const buildAxios = new AxiosBuilder()
+ .withBaseURL(BaseURL)
+ .withResponseType("json")
+ .withTimeout(120000);
+
+ if (isAuthenticated) {
+ buildAxios.withHeaders({
+ Authorization: "Bearer " + token,
+ });
+ }
+
+ const build_Axios = buildAxios.build();
+
+ build_Axios.interceptors.response.use(
+ function (response: any) {
+ const responseMsg = response?.data?.message;
+ const method = response.config.method;
+
+ const key = response.config.headers[HEADER_KEY];
+ const ResponseMessage =
+ responseMsg || t("validation.the_possess_done_successful");
+ if (method !== AxiosQueryEnum?.GET) {
+ queryClient.invalidateQueries(key);
+ toast.success(ResponseMessage);
+ setValidation([{}]);
+ setObjectToEdit([])
+ }
+
+ return response;
+ },
+ function (error) {
+ const status = error?.request?.status;
+ const errorMsg = error?.response?.data?.message;
+ const errorField = error?.response?.data;
+ const method = error.config.method;
+
+ if (status === AxiosStatusEnum.VALIDATION) {
+ setValidation(errorMsg ?? errorField);
+ const errorMessage = errorMsg || t("validation.some_thing_went_wrong");
+ toast.error(errorMessage);
+ }
+ if (status === AxiosStatusEnum.AUTHENTICATED) {
+ logout();
+ navigate("/auth");
+ }
+
+ if (method !== AxiosQueryEnum?.GET) {
+ const errorMessage = errorMsg || t("validation.some_thing_went_wrong");
+ toast.error(errorMessage);
+ return Promise.reject(error);
+ }
+ },
+ );
+ return build_Axios;
+
+ // return buildAxios.build();
+}
+
+export default useAxios;
diff --git a/src/api/helper/useDeleteMutation.ts b/src/api/helper/useDeleteMutation.ts
new file mode 100644
index 0000000..c5fb446
--- /dev/null
+++ b/src/api/helper/useDeleteMutation.ts
@@ -0,0 +1,28 @@
+import { useMutation, UseMutationResult } from "react-query";
+import useAxios from "./useAxios";
+import { HEADER_KEY } from "../config";
+import { AxiosResponse } from "../../types/Axios";
+
+type DataToSend = {
+ id: number | string;
+};
+
+function useDeleteMutation(
+ key: any,
+ url: string,
+ message?: string,
+): UseMutationResult {
+ const axios = useAxios();
+ return useMutation(
+ async (dataToSend) => {
+ const { data } = await axios.delete(url + `/` + dataToSend?.id, {
+ headers: {
+ [HEADER_KEY]: key,
+ },
+ });
+ return data;
+ },
+ );
+}
+
+export default useDeleteMutation;
diff --git a/src/api/helper/useGetQuery.ts b/src/api/helper/useGetQuery.ts
new file mode 100644
index 0000000..e466018
--- /dev/null
+++ b/src/api/helper/useGetQuery.ts
@@ -0,0 +1,39 @@
+import { useQuery } from "react-query";
+import useAxios from "./useAxios";
+import { useLocation } from "react-router-dom";
+import { PaginationParams } from "../utils/PaginationParams";
+import { filterParams } from "../utils/filterParams";
+
+function useGetQuery(
+ KEY: string | string[],
+ url: string,
+ params: any = {},
+ options: any = {},
+) {
+ const axios = useAxios();
+
+ const { show, pagination, ...remainingParams } = params;
+
+ const location = useLocation();
+
+ const { page, per_page } = PaginationParams(location);
+
+ const param_to_send = pagination
+ ? { ...remainingParams, page: page, per_page: per_page }
+ : { ...remainingParams };
+
+ const filteredParams = filterParams(param_to_send);
+
+ return useQuery(
+ [KEY, filteredParams, show],
+ async () => {
+ const response = await axios.get(url + (show ? `/${show}` : ""), {
+ params: filteredParams,
+ });
+ return response?.data ?? [];
+ },
+ options,
+ );
+}
+
+export default useGetQuery;
diff --git a/src/api/helper/useUpdateMutation.ts b/src/api/helper/useUpdateMutation.ts
new file mode 100644
index 0000000..195c32f
--- /dev/null
+++ b/src/api/helper/useUpdateMutation.ts
@@ -0,0 +1,36 @@
+import { useMutation, UseMutationResult } from "react-query";
+import useAxios from "./useAxios";
+import { HEADER_KEY } from "../config";
+import { AxiosResponse } from "../../types/Axios";
+
+const useUpdateMutation = (
+ key: string,
+ url: string,
+ message?: string,
+): UseMutationResult => {
+ const axios = useAxios();
+
+ return useMutation(async (dataToSend) => {
+ let request = null;
+ let id = null;
+
+ if (dataToSend instanceof FormData) {
+ dataToSend.append("_method", "PUT");
+ request = dataToSend;
+ id = dataToSend.get("id");
+ } else {
+ request = { ...dataToSend, _method: "PUT" };
+ id = dataToSend?.id;
+ }
+
+ const { data } = await axios.post(url + `/` + id, request, {
+ headers: {
+ "Content-Type": "multipart/form-data",
+ [HEADER_KEY]: key,
+ },
+ });
+ return data;
+ });
+};
+
+export default useUpdateMutation;
diff --git a/src/api/setting.ts b/src/api/setting.ts
new file mode 100644
index 0000000..1ac545f
--- /dev/null
+++ b/src/api/setting.ts
@@ -0,0 +1,22 @@
+
+import useGetQuery from "./helper/useGetQuery";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `restaurant`,
+ GET_ALL: `restaurant`,
+ DELETE: `restaurant`,
+ UPDATE: `restaurant`,
+
+};
+const KEY = "restaurant"
+
+
+export const useGetSetting = (params?:any,option?:any) => useGetQuery(KEY, API.GET_ALL,params);
+
+export const useAddSetting = () => useAddMutation(KEY, API.ADD);
+export const useUpdateSetting = (method?:any) => useUpdateMutation(KEY, API.UPDATE);
+
+export const useDeleteSetting = () =>useDeleteMutation(KEY, API.DELETE);
diff --git a/src/api/utils/PaginationParams.ts b/src/api/utils/PaginationParams.ts
new file mode 100644
index 0000000..6b1f83a
--- /dev/null
+++ b/src/api/utils/PaginationParams.ts
@@ -0,0 +1,7 @@
+export function PaginationParams(location: any) {
+ const searchParams = new URLSearchParams(location?.search);
+ return {
+ page: searchParams.get("page") || "",
+ per_page: searchParams.get("per_page") || "",
+ };
+}
diff --git a/src/api/utils/filterParams.ts b/src/api/utils/filterParams.ts
new file mode 100644
index 0000000..1381ae3
--- /dev/null
+++ b/src/api/utils/filterParams.ts
@@ -0,0 +1,5 @@
+export function filterParams(params: any) {
+ return Object.fromEntries(
+ Object.entries(params ?? {}).filter(([_, value]) => value !== ""),
+ );
+}
diff --git a/src/api/utils/useSearchQuery.ts b/src/api/utils/useSearchQuery.ts
new file mode 100644
index 0000000..2f2f298
--- /dev/null
+++ b/src/api/utils/useSearchQuery.ts
@@ -0,0 +1,16 @@
+import { useState, useEffect } from "react";
+import { useLocation } from "react-router-dom";
+
+function useSearchQuery(paramName: string): [string, (value: string) => void] {
+ const location = useLocation();
+ const [queryValue, setQueryValue] = useState("");
+
+ useEffect(() => {
+ const searchParams = new URLSearchParams(location.search);
+ setQueryValue(searchParams.get(paramName) || "");
+ }, [location, paramName]);
+
+ return [queryValue, setQueryValue];
+}
+
+export default useSearchQuery;
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/Axios.ts b/src/enums/Axios.ts
new file mode 100644
index 0000000..2f966fd
--- /dev/null
+++ b/src/enums/Axios.ts
@@ -0,0 +1,10 @@
+export enum AxiosQueryEnum {
+ GET = "get",
+ POST = "post",
+ DELETE = "delete",
+}
+
+export enum AxiosStatusEnum {
+ VALIDATION = 422,
+ AUTHENTICATED = 401,
+}
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/QueryStatus.ts b/src/enums/QueryStatus.ts
new file mode 100644
index 0000000..31cbdef
--- /dev/null
+++ b/src/enums/QueryStatus.ts
@@ -0,0 +1,5 @@
+export enum QueryStatusEnum {
+ LOADING = "loading",
+ ERROR = "error",
+ SUCCESS = "success",
+}
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/enums/Validation.ts b/src/enums/Validation.ts
new file mode 100644
index 0000000..8dcca3d
--- /dev/null
+++ b/src/enums/Validation.ts
@@ -0,0 +1,7 @@
+export enum Payments {
+ MAX_VALUE = 900000,
+}
+
+export enum Exam {
+ MAX_VALUE = 10000,
+}
diff --git a/src/enums/params.ts b/src/enums/params.ts
new file mode 100644
index 0000000..9a68120
--- /dev/null
+++ b/src/enums/params.ts
@@ -0,0 +1,8 @@
+export enum ParamsEnum {
+ STUDENT_ID = "student_id",
+ COURSE_ID = "course_id",
+ EDUCATION_CLASS_ID = "edu_class_id",
+ SUBJECT_ID = "subject_id",
+ BRANCH_ID = "branch_id",
+ CYCLE_ID = "cycle_id",
+}
diff --git a/src/index.tsx b/src/index.tsx
new file mode 100644
index 0000000..15a09ab
--- /dev/null
+++ b/src/index.tsx
@@ -0,0 +1,14 @@
+import App from './App';
+import 'bootstrap/dist/css/bootstrap.min.css';
+import './Styles/AppStyle/Import.scss'
+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..4320c63
--- /dev/null
+++ b/src/lib/ReactQueryProvider.tsx
@@ -0,0 +1,18 @@
+import React from "react";
+import { QueryClient, QueryClientProvider } from "react-query";
+
+function QueryProvider({ children }: any) {
+ const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ refetchOnWindowFocus: false,
+ },
+ },
+ });
+
+ return (
+ {children}
+ );
+}
+
+export default QueryProvider;
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/statemangment/AuthState.ts b/src/lib/statemangment/AuthState.ts
new file mode 100644
index 0000000..b2bd147
--- /dev/null
+++ b/src/lib/statemangment/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/statemangment/LayoutPagestate.ts b/src/lib/statemangment/LayoutPagestate.ts
new file mode 100644
index 0000000..db1c4b5
--- /dev/null
+++ b/src/lib/statemangment/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/statemangment/Pages/Products.ts b/src/lib/statemangment/Pages/Products.ts
new file mode 100644
index 0000000..4679b15
--- /dev/null
+++ b/src/lib/statemangment/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/statemangment/driver&customer/ModelState.tsx b/src/lib/statemangment/driver&customer/ModelState.tsx
new file mode 100644
index 0000000..4a4ee9c
--- /dev/null
+++ b/src/lib/statemangment/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/Axios.ts b/src/types/Axios.ts
new file mode 100644
index 0000000..c59cb16
--- /dev/null
+++ b/src/types/Axios.ts
@@ -0,0 +1,3 @@
+export type AxiosResponse = {
+ message?: string;
+};
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/types/item.ts b/src/types/item.ts
new file mode 100644
index 0000000..07860c8
--- /dev/null
+++ b/src/types/item.ts
@@ -0,0 +1,49 @@
+export interface Restaurant {
+ id: number;
+ name: string;
+ address: string;
+ logo: string;
+ slogan: {
+ text: string;
+ };
+ contact_info: {
+ phone_number: string;
+ email: string;
+ };
+ attributes: {
+ attribute: string;
+ };
+ video: string;
+ design_system: {
+ primary_color: string;
+ secondry_color: string;
+ };
+ location: {
+ location: string;
+ };
+ images: any[]; // Assuming the images array contains objects, replace 'any' with appropriate type if known
+ categories: Category[];
+ offers: Offer[];
+ uuid: string;
+ created_at: string;
+ updated_at: string;
+}
+
+interface Category {
+ id: number;
+ name: string;
+ image: string;
+ restaurant_id: number;
+ meals_count: number;
+ uuid: string;
+}
+
+interface Offer {
+ id: number;
+ name: string;
+ description: string;
+ image: string;
+ price: number;
+ restaurant_id: number;
+ uuid: string;
+}
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/Equal.ts b/src/utils/Array/Equal.ts
new file mode 100644
index 0000000..e69de29
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/convertArrayToJsonString.ts b/src/utils/Array/convertArrayToJsonString.ts
new file mode 100644
index 0000000..d6b40af
--- /dev/null
+++ b/src/utils/Array/convertArrayToJsonString.ts
@@ -0,0 +1,13 @@
+interface KeyValue {
+ key: string;
+ value: any;
+ }
+
+ export function convertArrayToJsonString(array: KeyValue[]): string {
+ const jsonObject: { [key: string]: any } = {};
+ array.forEach(item => {
+ jsonObject[item.key] = item.value;
+ });
+ return JSON.stringify(jsonObject);
+ }
+
\ 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/Array/isItArrayOfString.ts b/src/utils/Array/isItArrayOfString.ts
new file mode 100644
index 0000000..caa7aaf
--- /dev/null
+++ b/src/utils/Array/isItArrayOfString.ts
@@ -0,0 +1,12 @@
+export const isItArrayOfString = (data:any[])=>{
+ if(data?.length < 1){
+ return true
+ }
+
+ const filteredArray = data?.filter((item:any)=>{ return typeof item !== "string"})
+ if(filteredArray?.length < 1){
+ return true
+ }
+ return false;
+
+ }
\ 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/utils/object/objectToArray.ts b/src/utils/object/objectToArray.ts
new file mode 100644
index 0000000..4c9d98d
--- /dev/null
+++ b/src/utils/object/objectToArray.ts
@@ -0,0 +1,9 @@
+export interface KeyAndValue {
+ key: string;
+ value: any;
+}
+
+export function objectToArray(obj: Record): KeyAndValue[] {
+ if(!obj){ return [] }
+ return Object.keys(obj).map((key: string) => ({ key, value: obj[key] }));
+}
\ 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"
+ ]
+}
diff --git a/vite.config.js b/vite.config.js
new file mode 100644
index 0000000..4e690eb
--- /dev/null
+++ b/vite.config.js
@@ -0,0 +1,11 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+
+export default defineConfig(() => {
+ return {
+ build: {
+ outDir: 'build',
+ },
+ plugins: [react()],
+ };
+});
\ No newline at end of file