diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..894437f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+pnpm-lock.ymal
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-lock.yaml
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..6a521b2
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,11 @@
+{
+ "cSpell.words": [
+ "aldeen",
+ "Datepicker",
+ "formik",
+ "Karim",
+ "queryqlent",
+ "szhsin",
+ "Viewelement"
+ ]
+}
\ No newline at end of file
diff --git a/db.json b/db.json
new file mode 100644
index 0000000..7d19fac
--- /dev/null
+++ b/db.json
@@ -0,0 +1,76 @@
+{
+ "example": [
+ {
+ "id": 1,
+ "name": "ibrahim",
+ "email": "ibrahim@gmail.com"
+ },
+ {
+ "id": 2,
+ "name": "gregr",
+ "email": "ibrahimgmail.com"
+ },
+ {
+ "id": 3,
+ "name": "mhmad",
+ "email": "mhmad@gmial.com"
+ },
+ {
+ "id": 4,
+ "name": "soso",
+ "email": "soso@gmail.com"
+ },
+ {
+ "id": 5,
+ "name": "few",
+ "email": "jfpwrej"
+ },
+ {
+ "id": 6,
+ "name": "sos",
+ "email": "fdwf"
+ },
+ {
+ "id": 7,
+ "name": "sos",
+ "email": "fdwf"
+ },
+ {
+ "id": 8,
+ "name": "sos",
+ "email": "fdwf"
+ }
+ ],
+ "test2":[
+
+
+ {
+ "id":1,
+ "email":"admin@adamin.com"
+ }
+ ,
+ {
+ "id":1,
+ "email":"admin@adamin.com"
+ }
+ ,
+ {
+ "id":1,
+ "email":"admin@adamin.com"
+ }
+
+ , {
+ "id":1,
+ "email":"admin@adamin.com"
+ }
+
+ ],
+ "users": [
+ {
+ "id": 1,
+ "email": "admin@adamin.com",
+ "password": "password",
+ "token": "token"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..6084c26
--- /dev/null
+++ b/package.json
@@ -0,0 +1,104 @@
+{
+ "name": "my-app",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@ant-design/icons": "^4.8.3",
+ "@emotion/styled": "^11.11.0",
+ "@mui/icons-material": "^5.14.19",
+ "@mui/x-charts": "^6.19.4",
+ "@react-google-maps/api": "^2.19.2",
+ "@szhsin/react-menu": "github:szhsin/react-menu",
+ "@testing-library/jest-dom": "^5.17.0",
+ "@testing-library/react": "^13.4.0",
+ "@testing-library/user-event": "^13.5.0",
+ "@tinymce/tinymce-react": "^4.3.2",
+ "@types/jest": "^27.5.2",
+ "@types/node": "^16.18.60",
+ "@types/react": "^18.2.33",
+ "@types/react-dom": "^18.2.14",
+ "@types/socket.io-client": "^3.0.0",
+ "@wojtekmaj/react-daterange-picker": "^5.4.4",
+ "antd": "^5.12.1",
+ "apexcharts": "^3.44.2",
+ "axios": "^1.6.0",
+ "bootstrap": "^5.3.2",
+ "chart.js": "^4.4.0",
+ "dayjs": "^1.11.10",
+ "formik": "^2.4.5",
+ "history": "^5.3.0",
+ "i18next": "^23.6.0",
+ "i18next-browser-languagedetector": "^7.1.0",
+ "json-server": "^0.17.4",
+ "moment": "^2.30.1",
+ "prop-types": "^15.8.1",
+ "react": "^18.2.0",
+ "react-apexcharts": "^1.4.1",
+ "react-bootstrap": "^2.9.1",
+ "react-bootstrap-sweetalert": "^5.2.0",
+ "react-chartjs-2": "^5.2.0",
+ "react-confirm-alert": "^3.0.6",
+ "react-data-table-component": "^7.5.4",
+ "react-dom": "^18.2.0",
+ "react-feather": "^2.0.10",
+ "react-i18next": "^13.3.1",
+ "react-icons": "^4.11.0",
+ "react-input-range": "^1.3.0",
+ "react-number-format": "^5.3.4",
+ "react-query": "^3.39.3",
+ "react-redux": "^8.1.3",
+ "react-router-dom": "^6.18.0",
+ "react-scripts": "5.0.1",
+ "react-select": "^5.7.7",
+ "react-simple-star-rating": "^5.1.7",
+ "react-switch": "^7.0.0",
+ "react-tabs": "^6.0.2",
+ "react-toastify": "^9.1.3",
+ "react-toggle": "^4.1.3",
+ "reactstrap": "^9.2.0",
+ "redux": "^4.2.1",
+ "sass": "^1.69.5",
+ "socket.io-client": "^4.7.2",
+ "styled-components": "5.3.3",
+ "ts-xlsx": "^0.0.11",
+ "typescript": "^4.9.5",
+ "web-vitals": "^2.1.4",
+ "xlsx": "^0.18.5",
+ "yup": "^1.3.2",
+ "zustand": "^4.4.5"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject",
+ "g:api": "node src/Extensions/FileGenerator/generateApi.js",
+ "g:column": "node src/Extensions/FileGenerator/generateColumn.js",
+ "g:formutil": "node src/Extensions/FileGenerator/generateformUtils.js",
+ "g:page": "node src/Extensions/FileGenerator/generatePage.js",
+ "g:dashboard": "node src/Extensions/FileGenerator/generateDashboard.js ",
+ "g:modal:add": "node src/Extensions/FileGenerator/generateEditModal.js ",
+ "g:model:edit": "node src/Extensions/FileGenerator/generateEditModal.js "
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ },
+ "devDependencies": {
+ "@types/react-toggle": "^4.0.5"
+ }
+}
diff --git a/public/Layout/Ar.svg b/public/Layout/Ar.svg
new file mode 100644
index 0000000..c409129
--- /dev/null
+++ b/public/Layout/Ar.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/Layout/En.svg b/public/Layout/En.svg
new file mode 100644
index 0000000..b1db6ff
--- /dev/null
+++ b/public/Layout/En.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/Layout/LoginBg.jpg b/public/Layout/LoginBg.jpg
new file mode 100644
index 0000000..fc3a090
Binary files /dev/null and b/public/Layout/LoginBg.jpg differ
diff --git a/public/Logo.svg b/public/Logo.svg
new file mode 100644
index 0000000..eb87722
--- /dev/null
+++ b/public/Logo.svg
@@ -0,0 +1,82 @@
+
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..ce82bbd
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ Point - App
+
+
+
+
+
+
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/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..0247df7
--- /dev/null
+++ b/src/Components/Columns/ColumnsImage.tsx
@@ -0,0 +1,97 @@
+import {
+ DownloadOutlined,
+ RotateLeftOutlined,
+ RotateRightOutlined,
+ SwapOutlined,
+ ZoomInOutlined,
+ ZoomOutOutlined,
+} from '@ant-design/icons';
+import React from 'react';
+import { Image, Space } from 'antd';
+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 = 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 = (url:any) => {
+
+ fetch(url)
+ .then((response) => {
+ if (!response.ok) {
+ throw new Error('Network response was not ok');
+ }
+ return response.blob();
+ })
+ .then((blob) => {
+ const link = document.createElement('a');
+ link.href = URL.createObjectURL(blob);
+
+ // Extract file name from URL
+ const fileName = url.split('/').pop();
+ link.download = fileName || 'download'; // If file name cannot be extracted, set a default name
+
+ document.body.appendChild(link);
+ link.click();
+ URL.revokeObjectURL(link.href);
+ link.remove();
+ })
+ .catch((error) => {
+ console.error('Error fetching resource:', error);
+ });
+ };
+
+
+ return (
+ (
+
+ {/* */}
+
+
+
+
+
+
+
+ ),
+ }}
+ onError={handleError}
+
+ />
+ );
+};
+
+export default ColumnsImage;
+
+
+
+
+
+
+
+// {
+// name: t("image"),
+// center: "true",
+// cell: (row: any) => {
+// return (
+//
+// )
+// }
+// },
\ No newline at end of file
diff --git a/src/Components/Columns/ColumnsSwitch.tsx b/src/Components/Columns/ColumnsSwitch.tsx
new file mode 100644
index 0000000..1b155b4
--- /dev/null
+++ b/src/Components/Columns/ColumnsSwitch.tsx
@@ -0,0 +1,42 @@
+import { Switch } from 'antd'
+import React from 'react'
+import { CheckOutlined, CloseOutlined } from '@ant-design/icons';
+import { useFormikContext } from 'formik';
+export interface ColumnsSwitchProps {
+ name: string;
+ Front?: string;
+ Back?: string;
+ onChange?: (checked:any,event:any) => any;
+ icon?: boolean
+ Checked?:boolean
+
+}
+const ColumnsSwitch = (props: ColumnsSwitchProps) => {
+ const { name, Front, Back, icon, onChange } = props;
+ const formik = useFormikContext();
+ const onSwitchChange = (checked: boolean, event: Event) => {
+ // formik.setFieldValue("status", checked)
+
+
+
+ };
+ return (
+ : Front}
+ unCheckedChildren={icon ? : Back}
+ onChange={ (checked:any,event:any)=> onChange ? onChange(checked,event) : onSwitchChange(checked,event)}
+ />
+ )
+}
+
+export default ColumnsSwitch
+
+
+ColumnsSwitch.defaultProps = {
+ Front: "Front",
+ Back: "Back",
+ onChange: undefined,
+ icon: false,
+ Checked:false
+
+};
\ No newline at end of file
diff --git a/src/Components/Ui/Alert.tsx b/src/Components/Ui/Alert.tsx
new file mode 100644
index 0000000..c232160
--- /dev/null
+++ b/src/Components/Ui/Alert.tsx
@@ -0,0 +1,50 @@
+import React from "react";
+import { confirmAlert } from "react-confirm-alert";
+import SweetAlert from "react-bootstrap-sweetalert";
+import { useTranslation } from "react-i18next";
+
+export default function CustomConfirmAlert(options : any) {
+ confirmAlert({
+ customUI: ({ onClose }) => ,
+ });
+}
+
+type CustomUIProps ={
+ onClose :()=> void
+ options:{
+ title?:string
+ confirmBtnText:string
+ cancelBtnText:string
+ body:string
+ onConfirm:()=>void
+
+
+ }
+}
+function CustomUI({ onClose, options }:CustomUIProps) {
+
+
+ const [t] = useTranslation()
+ return (
+
+ {
+ options.onConfirm();
+ onClose();
+ }}
+ onCancel={onClose}
+
+ />
+
+
+ );
+}
diff --git a/src/Components/Ui/CheckboxesVuexy.tsx b/src/Components/Ui/CheckboxesVuexy.tsx
new file mode 100644
index 0000000..5bc635e
--- /dev/null
+++ b/src/Components/Ui/CheckboxesVuexy.tsx
@@ -0,0 +1,49 @@
+import React from 'react';
+
+interface CheckBoxesVuexyProps {
+ className?: string;
+ color: string;
+ defaultChecked?: boolean;
+ checked?: boolean;
+ value?: string;
+ disabled?: boolean;
+ onClick?: () => void;
+ onChange?: () => void;
+ size?: string;
+ icon: React.ReactNode;
+ label: string;
+}
+
+const CheckBoxesVuexy: React.FC = ({
+ className = '',
+ color,
+ defaultChecked,
+ checked,
+ value,
+ disabled,
+ onClick,
+ onChange,
+ size = 'md',
+ icon,
+ label,
+}) => {
+ return (
+
+
+
+ {icon}
+
+ {label}
+
+ );
+};
+
+export default CheckBoxesVuexy;
diff --git a/src/Components/Ui/FileInput.tsx b/src/Components/Ui/FileInput.tsx
new file mode 100644
index 0000000..94c5df0
--- /dev/null
+++ b/src/Components/Ui/FileInput.tsx
@@ -0,0 +1,27 @@
+import React from 'react'
+import 'bootstrap/dist/css/bootstrap.min.css';
+import { Input } from 'reactstrap';
+import { useFormikContext } from 'formik';
+
+type FileInputProps = {
+ name:string,
+ label:string,
+ accept:string,
+ onChange:any
+}
+function FileInput({name , accept="image/*" ,label , onChange} :FileInputProps) {
+
+
+ return (
+
+
+
+
+
+ )
+}
+
+export default FileInput
\ No newline at end of file
diff --git a/src/Components/Ui/HovarableImage.tsx b/src/Components/Ui/HovarableImage.tsx
new file mode 100644
index 0000000..c56b31c
--- /dev/null
+++ b/src/Components/Ui/HovarableImage.tsx
@@ -0,0 +1,37 @@
+import React from "react";
+import { Tooltip } from "reactstrap";
+
+const tooltipStyle = {
+ backgroundColor: "white",
+ border: "2px solid lightgrey",
+ maxWidth: "400px",
+};
+
+const HovarableImage = ({ id, src, imgPreviewProps = {}, ...props }:any) => {
+ const [isOpen, setIsOpen] = React.useState(false);
+ const ID = `image_hover_tooltip_${id}`;
+ const toggleTooltip = React.useCallback(() => setIsOpen((prev) => !prev), []);
+
+ return (
+
+

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

+ ) : (
+
{t("image_preview")}
+ )}
+
+ );
+};
+
+export default ImagePreview;
diff --git a/src/Components/Ui/LoadingButton.tsx b/src/Components/Ui/LoadingButton.tsx
new file mode 100644
index 0000000..248c486
--- /dev/null
+++ b/src/Components/Ui/LoadingButton.tsx
@@ -0,0 +1,13 @@
+import React from "react";
+import { Button, Spinner } from "reactstrap";
+
+const LoadingButton = ({ isLoading = false, ...props }) => {
+ return (
+
+ );
+};
+
+export { LoadingButton };
diff --git a/src/Components/Ui/LoadingSpinner.tsx b/src/Components/Ui/LoadingSpinner.tsx
new file mode 100644
index 0000000..efa5055
--- /dev/null
+++ b/src/Components/Ui/LoadingSpinner.tsx
@@ -0,0 +1,10 @@
+import { Spin } from 'antd'
+import React from 'react'
+
+function LoadingSpinner() {
+ return (
+
+ )
+}
+
+export default LoadingSpinner
\ No newline at end of file
diff --git a/src/Components/Ui/PasswordField/PasswordField.tsx b/src/Components/Ui/PasswordField/PasswordField.tsx
new file mode 100644
index 0000000..32489d7
--- /dev/null
+++ b/src/Components/Ui/PasswordField/PasswordField.tsx
@@ -0,0 +1,57 @@
+import React, { FC, useState } from "react";
+import { ErrorMessage, useField, Field } from "formik";
+import { FormGroup } from "reactstrap";
+// import PropTypes from "prop-types";
+import { Eye, EyeOff } from "react-feather";
+import "./index.css";
+
+interface PasswordFieldProps {
+ name: string;
+ label?: string;
+}
+
+const PasswordField: FC = ({ name, label, ...props }) => {
+ const [field, meta] = useField({ name, ...props });
+ const [showPassword, setShowPassword] = useState(false);
+ const EyeIcon = showPassword ? Eye : EyeOff;
+
+ const toggleShow = () => {
+ setShowPassword((prev) => !prev);
+ };
+
+ return (
+ <>
+ {label && }
+
+
+
+
+
+
+
+ >
+ );
+};
+
+// PasswordField.propTypes = {
+// name: PropTypes.string.isRequired,
+// };
+
+export { PasswordField };
\ No newline at end of file
diff --git a/src/Components/Ui/PasswordField/index.css b/src/Components/Ui/PasswordField/index.css
new file mode 100644
index 0000000..7a26d93
--- /dev/null
+++ b/src/Components/Ui/PasswordField/index.css
@@ -0,0 +1,10 @@
+.back-icon {
+ font-size: 18px;
+ margin: 0;
+ margin-right: 5px;
+}
+
+.back-btn {
+ padding-left: 0.8rem;
+ padding-right: 1rem;
+}
diff --git a/src/Components/Ui/ProgressBar.tsx b/src/Components/Ui/ProgressBar.tsx
new file mode 100644
index 0000000..146339f
--- /dev/null
+++ b/src/Components/Ui/ProgressBar.tsx
@@ -0,0 +1,24 @@
+import React from "react";
+import { Progress } from "reactstrap";
+
+const ProgressBar = ({ value,isLoading, isSuccess, isError }:any) => {
+
+
+ let color = "";
+ if (!isLoading && isSuccess) {
+ color = "success";
+ }
+ if (!isLoading && isError) {
+ color = "danger";
+ }
+ return (
+
+ );
+};
+
+
+export default ProgressBar;
diff --git a/src/Components/Ui/SelectField.tsx b/src/Components/Ui/SelectField.tsx
new file mode 100644
index 0000000..f794e31
--- /dev/null
+++ b/src/Components/Ui/SelectField.tsx
@@ -0,0 +1,29 @@
+import React from "react";
+import Select from "react-select";
+import { ValidatedField } from "./ValidatedField";
+import { useFormikContext } from "formik";
+
+const SelectField = ({ label, name, options, ...props }:any) => {
+ const formik = useFormikContext();
+
+ return (
+ opt.value === formik?.values[name]) || ""}
+ onChange={(opt:any) => formik.setFieldValue(name, opt.value)}
+ onBlur={() => formik.setFieldTouched(name)}
+ key={name}
+ {...props}
+ />
+ );
+};
+
+
+export default SelectField;
+
+
diff --git a/src/Components/Ui/StaticsCard/StaticCard.tsx b/src/Components/Ui/StaticsCard/StaticCard.tsx
new file mode 100644
index 0000000..bd5fddc
--- /dev/null
+++ b/src/Components/Ui/StaticsCard/StaticCard.tsx
@@ -0,0 +1,58 @@
+import React from "react";
+import { Card, CardBody } from "reactstrap";
+import { ChartTypeEnum } from "../../../enums/ChartTypeEnum";
+import { history } from "../../../ProviderContainer";
+import { useNavigate } from "react-router-dom";
+
+interface StatisticsCardProps {
+ className?: string;
+ iconLeft?: boolean;
+ icon: React.ReactNode;
+ count?: string;
+ CardTitle?: string;
+ CardContent?: string;
+ height?: number;
+ pathWhenClick :string ;
+
+}
+
+const StatisticsCard = (props :StatisticsCardProps) => {
+
+ const navigate = useNavigate()
+ const {
+ className,
+ iconLeft = false ,
+ icon,
+ count,
+ CardTitle,
+ CardContent,
+ pathWhenClick,
+ height,
+ ...rest
+ } = props;
+
+ return (
+ navigate(pathWhenClick )}>
+
+
+
+ {/*
{CardTitle}
*/}
+
{icon}
+
+
+
+ {/*
{count}
*/}
+
{CardContent}
+
+
+
+ );
+};
+
+export default StatisticsCard;
diff --git a/src/Components/Ui/StatusBadge.tsx b/src/Components/Ui/StatusBadge.tsx
new file mode 100644
index 0000000..1fb55e6
--- /dev/null
+++ b/src/Components/Ui/StatusBadge.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+import { Badge } from "reactstrap";
+
+const StatusBadge = ({ status }:any) => {
+ const [t] = useTranslation();
+
+ return (
+
+ {status ? t("active") : t("inacticve")}
+
+ );
+};
+
+
+
+export default StatusBadge;
diff --git a/src/Components/Ui/TableActions.tsx b/src/Components/Ui/TableActions.tsx
new file mode 100644
index 0000000..73c9563
--- /dev/null
+++ b/src/Components/Ui/TableActions.tsx
@@ -0,0 +1,38 @@
+import React , {ReactNode} from "react";
+import confirmAlert from "./Alert";
+import { FaEdit, FaTrash } from "react-icons/fa";
+
+type TableActionsProps = {
+ onDelete: () => any;
+ onEdit: () => void;
+ showEdit?: boolean;
+ showDelete?: boolean;
+ children?: ReactNode;
+};
+
+
+const TableActions = ({ onDelete , onEdit,showEdit=true,showDelete=true, children }:TableActionsProps) => {
+
+
+ return (
+
+ {showEdit && }
+ {showDelete && (
+
+ confirmAlert({
+ onConfirm: () => {
+ onDelete();
+
+ },
+ })
+ }
+ className="cursor-pointer"
+ size={20}
+ />
+ )}
+ {children}
+
+);
+};
+export default TableActions;
diff --git a/src/Components/Ui/ThreeSwitchState/TripleSwitch.tsx b/src/Components/Ui/ThreeSwitchState/TripleSwitch.tsx
new file mode 100644
index 0000000..c36ffbd
--- /dev/null
+++ b/src/Components/Ui/ThreeSwitchState/TripleSwitch.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import type { RadioChangeEvent } from 'antd';
+import { Radio } from 'antd';
+
+const onChange = (e: RadioChangeEvent) => {
+ console.log(`radio checked:${e.target.value}`);
+};
+
+const App: React.FC = () => (
+ <>
+
+
+
+ Hangzhou
+
+ Shanghai
+
+ Beijing
+ Chengdu
+
+
+
+ Hangzhou
+ Shanghai
+ Beijing
+ Chengdu
+
+ >
+);
+
+export default App;
diff --git a/src/Components/Ui/ToggleStatus.tsx b/src/Components/Ui/ToggleStatus.tsx
new file mode 100644
index 0000000..40df144
--- /dev/null
+++ b/src/Components/Ui/ToggleStatus.tsx
@@ -0,0 +1,39 @@
+import React from "react";
+import Toggle from "react-toggle";
+import "react-toggle/style.css";
+import StatusBadge from "./StatusBadge";
+import { useTranslation } from "react-i18next";
+
+interface ToggleStatusProps {
+
+}
+export const ToggleStatus = ({ object, handleSwitch, toggleMutation, ...props }:any) => {
+ const [t] = useTranslation();
+
+ // const handleSwitch = () => {
+ // toggleMutation.mutate({
+ // id: object.id,
+ // new_status: !object.is_active,
+ // });
+ // };
+
+ return (
+ <>
+
+
+ {object.is_active ? t("active") : t("inactive")}
+
+
+
+ >
+ );
+};
diff --git a/src/Components/Ui/ValidatedField.tsx b/src/Components/Ui/ValidatedField.tsx
new file mode 100644
index 0000000..c2bd089
--- /dev/null
+++ b/src/Components/Ui/ValidatedField.tsx
@@ -0,0 +1,64 @@
+import React from "react";
+import { ErrorMessage, useField, Field } from "formik";
+import { FormGroup } from "reactstrap";
+import { useTranslation } from "react-i18next";
+
+const ValidatedField = ({
+ name,
+ label,
+ CustomField,
+ icon: Icon,
+ optional,
+ labelIcon = null,
+ formProps,
+ isRequired,
+
+ ...props
+}:any) => {
+
+ const [field, meta] = useField({ name, ...props });
+ const [t] = useTranslation();
+
+ let Wrapper = Field;
+
+ if (CustomField) {
+ Wrapper = CustomField;
+ }
+ const fieldProps = props.type === "file" ? {} : { ...field };
+
+ return (
+ <>
+ {label && (
+
+ )}
+
+
+ {Icon && (
+
+
+
+ )}
+
+ {(msg) => {t(msg)}}
+
+
+ >
+ );
+};
+
+
+export { ValidatedField };
diff --git a/src/Components/Ui/index.tsx b/src/Components/Ui/index.tsx
new file mode 100644
index 0000000..ae6a6f0
--- /dev/null
+++ b/src/Components/Ui/index.tsx
@@ -0,0 +1,17 @@
+import Checkbox from './CheckboxesVuexy'
+import ImagePreview from './ImagePreview'
+import SelectField from './SelectField'
+import { useImagePreview } from './useImagePreview'
+import {ValidatedField} from './ValidatedField'
+import StatusBadge from './StatusBadge'
+import HovarableImage from './HovarableImage'
+
+export {
+ Checkbox,
+ ImagePreview,
+ SelectField,
+ useImagePreview,
+ ValidatedField,
+ StatusBadge,
+ HovarableImage
+}
\ No newline at end of file
diff --git a/src/Components/Ui/tables/Actions.tsx b/src/Components/Ui/tables/Actions.tsx
new file mode 100644
index 0000000..f78e1ad
--- /dev/null
+++ b/src/Components/Ui/tables/Actions.tsx
@@ -0,0 +1,58 @@
+import React , {ReactNode} from "react";
+import { FaEdit, FaEye, FaTrash } from "react-icons/fa";
+import CustomConfirmAlert from "../Alert";
+import { usePageState } from "../../../lib/state mangment/LayoutPagestate";
+
+type TableActionsProps = {
+ onDelete?: () => any;
+ onEdit?: () => any;
+ onView?:() => any;
+ showView?: boolean;
+ showEdit?: boolean;
+ showDelete?: boolean;
+ children?: ReactNode;
+ objectToEdit:any
+ className?:string
+
+};
+
+
+const TableActions = ({ onDelete=()=>{} , objectToEdit,onEdit=()=>{},onView,showEdit=true,showDelete=true,showView=true,children,className }:TableActionsProps) => {
+// const TableActions = ({ onDelete=()=>{} , objectToEdit,onEdit=()=>{},onView,showEdit=true,showDelete=true,showView=true,children }:TableActionsProps) => {
+
+ // console.log(objectToEdit);
+
+ const {setObjectToEdit , setIsOpenEditModel} = usePageState()
+ return (
+
+ {showEdit && {
+ setObjectToEdit(objectToEdit)
+ setIsOpenEditModel()
+ onEdit()
+
+ }} className="cursor-pointer m-2" size={20} />}
+ {showView && }
+
+
+ {showDelete && (
+
+ CustomConfirmAlert({
+ onConfirm: () => {
+
+
+ onDelete();
+
+ },
+ })
+ }
+ className="cursor-pointer"
+ size={20}
+ />
+ )}
+
+ {children}
+
+);
+};
+export default TableActions;
diff --git a/src/Components/Ui/tables/ConfirmAlert.tsx b/src/Components/Ui/tables/ConfirmAlert.tsx
new file mode 100644
index 0000000..bb99f66
--- /dev/null
+++ b/src/Components/Ui/tables/ConfirmAlert.tsx
@@ -0,0 +1,40 @@
+import React from "react";
+import { confirmAlert } from "react-confirm-alert";
+import SweetAlert from "react-bootstrap-sweetalert";
+
+interface CustomUIProps {
+ onClose: () => void;
+ options: {
+ title?: string;
+ confirmBtnText?: string;
+ cancelBtnText?: string;
+ onConfirm: () => void;
+ body?: string;
+ };
+}
+
+export default function CustomConfirmAlert(options: any) {
+ confirmAlert({
+ customUI: ({ onClose }) => ,
+ });
+}
+
+function CustomUI({ onClose, options }: CustomUIProps) {
+ const sweetAlertProps: any = {
+ title: options.title || `DELETE, Are you sure?`,
+ warning: true,
+ show: true,
+ showCancel: true,
+ reverseButtons: true,
+ cancelBtnBsStyle: "danger",
+ confirmBtnText: options.confirmBtnText || "Yes, delete it!",
+ cancelBtnText: options.cancelBtnText || "Cancel",
+ onConfirm: () => {
+ options.onConfirm();
+ onClose();
+ },
+ onCancel: onClose,
+ };
+
+ return {options.body || "You won't be able to revert this!"};
+}
diff --git a/src/Components/Ui/useImagePreview.tsx b/src/Components/Ui/useImagePreview.tsx
new file mode 100644
index 0000000..818c68e
--- /dev/null
+++ b/src/Components/Ui/useImagePreview.tsx
@@ -0,0 +1,24 @@
+import { useState, useEffect } from "react";
+
+export const useImagePreview = (defaultValue:any = null) => {
+ const [preview, setPreview] = useState(defaultValue || null);
+
+ useEffect(() => {
+ return () => {
+ URL.revokeObjectURL(preview);
+
+ };
+ }, [preview]);
+
+ const handleImageChange = (event:any) => {
+
+ setPreview(URL.createObjectURL(event.target.files[0]));
+
+ };
+
+ return {
+ preview,
+ handleImageChange,
+ setPreview,
+ };
+};
diff --git a/src/Components/Utils/BlockModal.tsx b/src/Components/Utils/BlockModal.tsx
new file mode 100644
index 0000000..d6c47f0
--- /dev/null
+++ b/src/Components/Utils/BlockModal.tsx
@@ -0,0 +1,62 @@
+
+import React, { useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
+import { BsExclamationCircle } from 'react-icons/bs';
+import { Button, Card, CardBody, Input, Label, Modal, ModalHeader } from 'reactstrap';
+import { useCommonModelState } from '../../lib/state mangment/driver&customer/ModelState';
+import { LoadingButton } from '../Ui/LoadingButton';
+
+interface BlockModelProps {
+ Mutation:any,
+ type :'customer' |'driver'
+}
+
+const BlockModel: React.FC = ({Mutation ,type}) => {
+ const {t} = useTranslation();
+ const key_to_api = type == t('customer') ? t('customer_id') : t("driver_id")
+
+ const {isOpenBlock:isOpen , objectID , setIsopenBlock:setIsOpen} = useCommonModelState()
+
+ const handleSubmit = () => {
+ const blockInput = document.getElementById('block_input') as HTMLInputElement;
+ if (blockInput) {
+ Mutation.mutate({ [key_to_api]: objectID, block_timer: blockInput.value });
+ }
+ };
+
+ useEffect(() => {
+ if (Mutation.isSuccess) {
+ setIsOpen();
+ }
+ }, [Mutation.isSuccess, setIsOpen]);
+
+ return (
+
+ setIsOpen()}>
+ {t("al")}{type}{t('_block_page')}
+
+
+
+
+
{t('blocking_')}{type}
+
+
+
+
+
+
+
+ {t('add_block_for_')}{type}
+
+
+
+
+
+
+
+ );
+};
+
+export default BlockModel;
diff --git a/src/Components/Utils/GiftModal.tsx b/src/Components/Utils/GiftModal.tsx
new file mode 100644
index 0000000..bbd8d3e
--- /dev/null
+++ b/src/Components/Utils/GiftModal.tsx
@@ -0,0 +1,63 @@
+import React, { useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
+import { BsExclamationCircle } from 'react-icons/bs';
+import { Button, Card, CardBody, Col, Input, Label, Modal, ModalHeader, Row } from 'reactstrap';
+import { useCommonModelState } from '../../lib/state mangment/driver&customer/ModelState';
+import { LoadingButton } from '../Ui/LoadingButton';
+
+
+interface GiftModalProps {
+ Mutation:any,
+ type :'customer' |'driver'
+}
+
+const GiftModal: React.FC = ({Mutation ,type }) => {
+ const {t} = useTranslation();
+
+ const {isOpenGift:isOpen , objectID , setIsopenGift:setIsOpen} = useCommonModelState()
+
+ useEffect(() => {
+ if (Mutation.isSuccess) {
+ setIsOpen();
+ }
+ }, [Mutation.isSuccess, setIsOpen]);
+
+ const handleGift = () => {
+ const enterCodesInput = document.getElementById('enter_codes') as HTMLInputElement;
+ if (enterCodesInput && enterCodesInput.value) {
+ Mutation.mutate({ type, id: objectID, value: enterCodesInput.value });
+ }
+ };
+
+ return (
+
+ setIsOpen()}>
+ {t("al")}{type} {t('_gift_page')}
+
+
+
+
+
+
+
+
+
+
+ {t('give')}
+
+
+
+
+
+
+
+ );
+};
+
+export default GiftModal;
diff --git a/src/Components/Utils/Loading/Loading.scss b/src/Components/Utils/Loading/Loading.scss
new file mode 100644
index 0000000..9ffb658
--- /dev/null
+++ b/src/Components/Utils/Loading/Loading.scss
@@ -0,0 +1,93 @@
+.Loading{
+
+ .wrapper {
+ width: 200px;
+ height: 60px;
+ position: relative;
+ left: 40%;
+ z-index: 1;
+ }
+
+ .circle {
+ width: 20px;
+ height: 20px;
+ position: absolute;
+ border-radius: 50%;
+ background-color: var(--primary);
+ left: 15%;
+ transform-origin: 50%;
+ animation: circle7124 .5s alternate infinite ease;
+ }
+
+ @keyframes circle7124 {
+ 0% {
+ top: 60px;
+ height: 5px;
+ border-radius: 50px 50px 25px 25px;
+ transform: scaleX(1.7);
+ }
+
+ 40% {
+ height: 20px;
+ border-radius: 50%;
+ transform: scaleX(1);
+ }
+
+ 100% {
+ top: 0%;
+ }
+ }
+
+ .circle:nth-child(2) {
+ left: 45%;
+ animation-delay: .2s;
+ }
+
+ .circle:nth-child(3) {
+ left: auto;
+ right: 15%;
+ animation-delay: .3s;
+ }
+
+ .shadow {
+ width: 20px;
+ height: 4px;
+ border-radius: 50%;
+ background-color: rgba(0,0,0,0.9);
+ position: absolute;
+ top: 62px;
+ transform-origin: 50%;
+ z-index: -1;
+ left: 15%;
+ filter: blur(1px);
+ animation: shadow046 .5s alternate infinite ease;
+ }
+
+ @keyframes shadow046 {
+ 0% {
+ transform: scaleX(1.5);
+ }
+
+ 40% {
+ transform: scaleX(1);
+ opacity: .7;
+ }
+
+ 100% {
+ transform: scaleX(.2);
+ opacity: .4;
+ }
+ }
+
+ .shadow:nth-child(4) {
+ left: 45%;
+ animation-delay: .2s
+ }
+
+ .shadow:nth-child(5) {
+ left: auto;
+ right: 15%;
+ animation-delay: .3s;
+ }
+
+}
diff --git a/src/Components/Utils/Loading/Loading.tsx b/src/Components/Utils/Loading/Loading.tsx
new file mode 100644
index 0000000..19651b4
--- /dev/null
+++ b/src/Components/Utils/Loading/Loading.tsx
@@ -0,0 +1,19 @@
+import React from 'react'
+import './Loading.scss'
+const Loading = () => {
+
+ return (
+
+ )
+}
+
+export default Loading
\ No newline at end of file
diff --git a/src/Components/Utils/SearchBar/SearchBar.scss b/src/Components/Utils/SearchBar/SearchBar.scss
new file mode 100644
index 0000000..6834dcf
--- /dev/null
+++ b/src/Components/Utils/SearchBar/SearchBar.scss
@@ -0,0 +1,43 @@
+.SearchBar{
+ .group {
+ display: flex;
+ align-items: center;
+ position: relative;
+ max-width: 190px;
+ }
+
+ .input {
+ width: 100%;
+ height: 40px;
+ padding: 0 1rem;
+ padding-left: 2.5rem;
+ border-radius: 8px;
+ outline: none;
+ font-weight: 500;
+ background: var(--primary);
+ color: var(--bg);
+ border: none;
+ box-shadow: 2px 2px 7px 0 var(--primary);
+
+ }
+
+ .input::placeholder {
+ color: var(--bg);
+ }
+
+
+
+ .icon {
+ position: absolute;
+ left: 1rem;
+ fill: var(--bg);
+ width: 1rem;
+ height: 1rem;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/Components/Utils/SearchBar/SearchBar.tsx b/src/Components/Utils/SearchBar/SearchBar.tsx
new file mode 100644
index 0000000..f1f5cd2
--- /dev/null
+++ b/src/Components/Utils/SearchBar/SearchBar.tsx
@@ -0,0 +1,14 @@
+import React from 'react'
+import './SearchBar.scss'
+const SearchBar = () => {
+ return (
+
+ )
+}
+
+export default SearchBar
\ No newline at end of file
diff --git a/src/Components/Utils/Theme.tsx b/src/Components/Utils/Theme.tsx
new file mode 100644
index 0000000..7681ffd
--- /dev/null
+++ b/src/Components/Utils/Theme.tsx
@@ -0,0 +1,84 @@
+import { Menu, MenuItem, MenuButton } from '@szhsin/react-menu';
+import { useTranslation } from 'react-i18next';
+import { usePageState } from '../../lib/state mangment/LayoutPagestate';
+import { BsFillMoonStarsFill, BsFillSunFill, BsSunglasses } from 'react-icons/bs';
+
+
+let What_the_Theme = localStorage.getItem('theme') ?? "light";
+
+if (What_the_Theme === "dark") {
+
+ document.body.classList.add('dark')}
+ else if (What_the_Theme === "glass") {
+
+ document.body.classList.add('glass')
+ }
+
+
+
+
+export default function Theme() {
+ const {t} = useTranslation();
+
+ const {setThemChange} = usePageState()
+
+ const changeTheme = (newTheme : any) => {
+
+
+ if(newTheme === "dark"){
+ document.body.classList.remove('glass');
+ document.body.classList.add('dark');localStorage.setItem("theme", "dark");
+ What_the_Theme = "dark"
+ }
+ else if(newTheme === "light"){
+ document.body.classList.remove('glass');
+ document.body.classList.remove('dark');localStorage.setItem("theme", "light");
+ What_the_Theme = "light"
+
+ }
+ else if(newTheme === "glass"){
+ document.body.classList.remove('dark'); document.body.classList.add('glass'); localStorage.setItem("theme", "glass");
+ What_the_Theme = "glass"
+
+ }
+ setThemChange()
+ };
+ /// BsSunglasses BsFillSunFill BsFillMoonStarsFill
+
+
+ return (
+
+
+
+
+ );
+}
diff --git a/src/Components/Utils/Translate.tsx b/src/Components/Utils/Translate.tsx
new file mode 100644
index 0000000..3dde7be
--- /dev/null
+++ b/src/Components/Utils/Translate.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { Menu, MenuItem, MenuButton } from '@szhsin/react-menu';
+import { useLanguage, useLanguageMenu } from '../../Hooks/useChangeLanguage';
+import i18next from 'i18next';
+
+export default function Translate() {
+ const { changeLanguage } = useLanguage();
+ const { languageOptions } = useLanguageMenu();
+
+ const handleLanguageChange = (newLanguage:string) => {
+ changeLanguage(newLanguage);
+ };
+
+ return (
+
+
+
+ );
+}
diff --git a/src/Components/Utils/UnBlockModal.tsx b/src/Components/Utils/UnBlockModal.tsx
new file mode 100644
index 0000000..cf3fac1
--- /dev/null
+++ b/src/Components/Utils/UnBlockModal.tsx
@@ -0,0 +1,60 @@
+
+import React, { useEffect } from 'react';
+import { BsExclamationCircle } from 'react-icons/bs';
+import { Button, Card, CardBody, Input, Label, Modal, ModalHeader } from 'reactstrap';
+import { useTranslation } from 'react-i18next';
+import { LoadingButton } from '../Ui/LoadingButton';
+import { useCommonModelState } from '../../lib/state mangment/driver&customer/ModelState';
+import { CiLock } from "react-icons/ci";
+
+interface UnBlockModalProps {
+
+ Mutation:any,
+ type :'customer' |'driver'
+}
+
+const UnBlockModal: React.FC = ({Mutation ,type }) => {
+ const {t} = useTranslation();
+
+ const key_to_api = type == t('customer') ? t('customer_id') : t("driver_id")
+
+ const {isOpenUnBlock:isOpen , objectID , setIsopenUnBlock:setIsopen} = useCommonModelState()
+
+ const handleSubmit = () => {
+ Mutation.mutate({ [key_to_api]: objectID });
+ };
+
+ useEffect(() => {
+ if (Mutation.isSuccess) {
+ setIsopen();
+ }
+ }, [Mutation.isSuccess, setIsopen]);
+
+ return (
+
+ setIsopen()}>
+ {t("al")}{type} {t('un_block_page')}
+
+
+
+
+
{t('un_blocking_')}{type}
+
+
+
+
+
+ {t('un_block_for_')}{type}
+
+
+
+
+
+
+
+ );
+};
+
+export default UnBlockModal;
diff --git a/src/Components/ValidationField/Ui/KarimSpinner.tsx b/src/Components/ValidationField/Ui/KarimSpinner.tsx
new file mode 100644
index 0000000..12206f9
--- /dev/null
+++ b/src/Components/ValidationField/Ui/KarimSpinner.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { Spin } from 'antd';
+
+interface Props {
+ loading: boolean;
+ children: React.ReactNode;
+ className?: string;
+}
+
+const KarimSpinner: React.FC = ({ loading, className, children }) => {
+ return (
+
+ {loading ?
: children}
+
+ );
+};
+
+export default KarimSpinner;
diff --git a/src/Components/ValidationField/Ui/SearchBar.scss b/src/Components/ValidationField/Ui/SearchBar.scss
new file mode 100644
index 0000000..2ddadd9
--- /dev/null
+++ b/src/Components/ValidationField/Ui/SearchBar.scss
@@ -0,0 +1,48 @@
+.SearchBar{
+ // margin-top: 20px;
+ .group {
+ display: flex;
+ align-items: center;
+ position: relative;
+ max-width: 350px;
+ width: 350px;
+
+ }
+
+ .input {
+ width: 100%;
+ height: 40px;
+ padding: 0 1rem;
+ padding-left: 2.5rem;
+ border-radius: 8px;
+ outline: none;
+ font-weight: 500;
+ background: var(--bg);
+ color: var(--text);
+ border: none;
+ box-shadow: 2px 2px 7px 0 var(--bg);
+
+ }
+
+ .input::placeholder {
+ color: var(--subtext);
+ opacity: .4;
+
+ }
+
+
+
+ .icon {
+ position: absolute;
+ left: 1rem;
+ fill: var(--subtext);
+ width: 1rem;
+ height: 1rem;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/Components/ValidationField/Ui/SearchBar.tsx b/src/Components/ValidationField/Ui/SearchBar.tsx
new file mode 100644
index 0000000..f70b289
--- /dev/null
+++ b/src/Components/ValidationField/Ui/SearchBar.tsx
@@ -0,0 +1,35 @@
+import React, { useState } from 'react'
+import './SearchBar.scss'
+import { useNavigate, useSearchParams } from 'react-router-dom';
+const SearchBar = () => {
+ const [searchQuery, setSearchQuery] = useState('');
+ const [searchParams] = useSearchParams()
+ const navigate = useNavigate();
+
+ const handleChange = (event:any) => {
+ const { value } = event.target;
+ setSearchQuery(value);
+ updateUrlParams(value);
+ };
+
+ const updateUrlParams = (value:any) => {
+ navigate(`?search=${value}`);
+
+
+ };
+
+ return (
+
+ )
+}
+
+export default SearchBar
\ No newline at end of file
diff --git a/src/Components/ValidationField/ValidationField.scss b/src/Components/ValidationField/ValidationField.scss
new file mode 100644
index 0000000..97e9f5e
--- /dev/null
+++ b/src/Components/ValidationField/ValidationField.scss
@@ -0,0 +1,78 @@
+.ValidationField{
+ >*{
+ width: 100%;
+ }
+ .text,.ant-form-item{
+ margin-bottom:7px !important;
+
+ }
+
+ >span{
+ margin-bottom: 0px !important;
+ &:focus-within{
+ border-color: var(--primary) ;
+ box-shadow: 0 0 0 1px var(--primary);
+ cursor: pointer;
+ }
+ &:has(.is-invalid){
+ border-color: red !important;
+
+ }
+ input{
+ color: var(--text);
+ background: var(--bg);
+ }
+
+input:-webkit-autofill,
+input:-webkit-autofill:hover,
+input:-webkit-autofill:focus,
+input:-webkit-autofill:active{
+ -webkit-box-shadow: 0 0 0 30px white inset !important;
+}
+ }
+}
+
+.ant-upload-select{
+ width: 100%;
+}
+.Checkboxs{
+ padding: 4%;
+}
+.SearchField{
+ button{
+ background: var(--primary);
+ }
+}
+.text{
+ color: var(--text);
+}
+
+input:disabled{
+ color: var(--text) !important;
+}
+
+.isError{
+ outline: red 1px solid;
+ color: red;
+}
+.Error_color{
+ color: red;
+
+}
+input:-webkit-autofill {
+ -webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
+}
+input:-webkit-autofill:focus {
+ -webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
+}
+
+/* Remove autofill background color on hover */
+input:-webkit-autofill:hover {
+ -webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
+}
+
+
+.ant-upload-list .ant-upload-list-item{
+ height:78px !important;
+ }
+
\ No newline at end of file
diff --git a/src/Components/ValidationField/ValidationField.tsx b/src/Components/ValidationField/ValidationField.tsx
new file mode 100644
index 0000000..6e25672
--- /dev/null
+++ b/src/Components/ValidationField/ValidationField.tsx
@@ -0,0 +1,34 @@
+import React from "react";
+import "./ValidationField.scss";
+import { Date, Time, File, DataRange, SelectField, Default, CheckboxField ,TextAreaField} from './View';
+import { ValidationFieldProps } from "./types";
+import MaltyFile from "./View/MaltyFile";
+import SearchField from "./View/SearchField";
+
+const ValidationField: React.FC = ({type , ...otherProps}) => {
+
+ switch (type) {
+ case 'Select':
+ return ;
+ case 'Search':
+ return ;
+ case "DataRange":
+ return ;
+ case "Date":
+ return ;
+ case "Time":
+ return ;
+ case "File":
+ return ;
+ case "MaltyFile":
+ return ;
+ case "Checkbox":
+ return ;
+ case "TextArea":
+ return ;
+ default:
+ return ;
+ }
+};
+
+export default React.memo(ValidationField);
diff --git a/src/Components/ValidationField/View/CheckboxField.tsx b/src/Components/ValidationField/View/CheckboxField.tsx
new file mode 100644
index 0000000..21c419e
--- /dev/null
+++ b/src/Components/ValidationField/View/CheckboxField.tsx
@@ -0,0 +1,36 @@
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+import { Checkbox, Form } from 'antd';
+
+const CheckboxField = ({ name, label, isDisabled, onChange,Group,className, props }: any) => {
+
+ const { t, formik,isError,errorMsg} = useFormField(name, props)
+ const CheckboxhandleChange = (value: any) => {
+ formik.setFieldValue(name, value?.target?.checked)
+
+ };
+ return (
+
+
+
+ {t(`${label ? label : name}`)}
+
+
+
+
+ )
+}
+
+export default CheckboxField
\ No newline at end of file
diff --git a/src/Components/ValidationField/View/DataRange.tsx b/src/Components/ValidationField/View/DataRange.tsx
new file mode 100644
index 0000000..742e6b5
--- /dev/null
+++ b/src/Components/ValidationField/View/DataRange.tsx
@@ -0,0 +1,44 @@
+import { Form, DatePicker } from 'antd'
+
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+
+const { RangePicker } = DatePicker;
+
+const DataRange = ({ name, label, Format, props, onChange, isDisabled, placeholder, className }: any) => {
+
+ const { errorMsg, isError, t, formik } = useFormField(name, props)
+ const onCalendarChange = (value: any) => {
+
+ formik.setFieldValue(name, value)
+
+ };
+ return (
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default DataRange
\ No newline at end of file
diff --git a/src/Components/ValidationField/View/Date.tsx b/src/Components/ValidationField/View/Date.tsx
new file mode 100644
index 0000000..1a21512
--- /dev/null
+++ b/src/Components/ValidationField/View/Date.tsx
@@ -0,0 +1,51 @@
+import { Form, DatePicker } from 'antd';
+import React from 'react';
+import useFormField from '../../../Hooks/useFormField';
+import dayjs from 'dayjs';
+
+const DateField = ({ name, label, picker = "date", isDisabled, props, onChange, placeholder, className, Format }: any) => {
+
+ const { errorMsg, isError, t, formik } = useFormField(name, props);
+
+ const onCalendarChange = (value: any) => {
+ formik.setFieldValue(name, value);
+ };
+
+ // Function to check if a date is valid
+ const isValidDate = (date: any) => {
+ return date && !isNaN(date.valueOf()) && dayjs(date).isValid();
+ };
+
+ // Set a default invalid date if the provided defaultValue is invalid
+ const getDefaultDate = () => {
+ const defaultValue = formik.values[name];
+ return isValidDate(defaultValue) ? defaultValue : null; // Set to null or any other default invalid date
+ };
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default DateField;
diff --git a/src/Components/ValidationField/View/Default.tsx b/src/Components/ValidationField/View/Default.tsx
new file mode 100644
index 0000000..1d0678d
--- /dev/null
+++ b/src/Components/ValidationField/View/Default.tsx
@@ -0,0 +1,36 @@
+import { Form, Input } from 'antd'
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+
+const Default = ({ name, label, placeholder, isDisabled, onChange, props,type }: any) => {
+ const { Field, formik, isError, errorMsg, t } = useFormField(name, props);
+
+
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default React.memo(Default);
+;
diff --git a/src/Components/ValidationField/View/File.tsx b/src/Components/ValidationField/View/File.tsx
new file mode 100644
index 0000000..f2816aa
--- /dev/null
+++ b/src/Components/ValidationField/View/File.tsx
@@ -0,0 +1,60 @@
+import { Button, Upload, UploadFile } from 'antd'
+import useFormField from '../../../Hooks/useFormField';
+import { UploadOutlined } from '@ant-design/icons';
+
+
+const File = ({ name, label, onChange, isDisabled,placholder,className, props }: any) => {
+ const { formik, t ,isError} = useFormField(name, props)
+ let FormikName = formik.values[name];
+
+ const fileList: UploadFile[] = [
+
+ {
+ uid: '-1',
+ name: '',
+ status: 'done',
+ url: FormikName,
+ thumbUrl: FormikName
+ }
+ ];
+ const FilehandleChange = (value:any) => {
+
+ formik.setFieldValue(name, value.file.originFileObj)
+
+ };
+ const customRequest = async ({ onSuccess}: any) => {
+ onSuccess();
+ };
+ return (
+
+
+
+
+ }>
+ {placholder ?? t("upload_image") }
+
+
+ {isError ? "required" : ""}
+
+
+
+
+
+ )
+}
+
+export default File
\ No newline at end of file
diff --git a/src/Components/ValidationField/View/MaltyFile.tsx b/src/Components/ValidationField/View/MaltyFile.tsx
new file mode 100644
index 0000000..55ece22
--- /dev/null
+++ b/src/Components/ValidationField/View/MaltyFile.tsx
@@ -0,0 +1,49 @@
+import { Button, Upload } from 'antd';
+import { UploadOutlined } from '@ant-design/icons';
+import useFormField from '../../../Hooks/useFormField';
+
+const MaltyFile = ({ name, label, onChange, isDisabled, placholder, className, props }: any) => {
+ const { formik, t, isError } = useFormField(name, props);
+ const fileList = formik?.values[name] ? formik?.values[name]?.map((file: any, index: number) => ({
+ uid: index,
+ name: file.name,
+ status: 'done',
+ url: file.url || '',
+ thumbUrl: file.url || '',
+ })) : [];
+
+ const FilehandleChange = ({ file, fileList }: any) => {
+ formik.setFieldValue(name, fileList.map((file: any) => file.originFileObj));
+ };
+
+ const customRequest = async ({ onSuccess }: any) => {
+ // Perform any necessary actions before onSuccess is called
+ onSuccess();
+ };
+
+ return (
+
+
+
+
+ }>
+ {placholder ?? t("upload_image")}
+
+ {isError ? "required" : ""}
+
+
+ );
+};
+
+export default MaltyFile;
diff --git a/src/Components/ValidationField/View/SearchField.tsx b/src/Components/ValidationField/View/SearchField.tsx
new file mode 100644
index 0000000..4b34de5
--- /dev/null
+++ b/src/Components/ValidationField/View/SearchField.tsx
@@ -0,0 +1,67 @@
+import { Form, Select } from 'antd';
+import React, { useEffect, useState } from 'react';
+import useFormField from '../../../Hooks/useFormField';
+import { useLocation, useNavigate } from 'react-router-dom';
+
+const SearchField = ({ name, label, placeholder, isDisabled, searchBy, option, isMulti, onChange, className, loading,props }: any) => {
+ const { errorMsg, isError, t, formik } = useFormField(name, props);
+ const [searchQuery, setSearchQuery] = useState('');
+ const location = useLocation()
+
+ const navigate = useNavigate()
+ useEffect(() => {
+ const searchParams = new URLSearchParams(window?.location?.search);
+ setSearchQuery(searchParams?.get('search') || '');
+ }, []);
+
+
+
+ const SelecthandleChange = (value: { value: string; label: React.ReactNode }) => {
+ formik?.setFieldValue(name, value);
+
+ console.log(value);
+ };
+ const SearchHandleChange = (value:any) => {
+ if (value || value !== "") {
+ navigate(`${window?.location?.pathname}?${searchBy}=${value}`);
+ } else {
+ const params = new URLSearchParams(location.search);
+ params.delete(searchBy ?? "search");
+ navigate(`${window?.location.pathname}?${params.toString()}`);
+ }
+
+ };
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default React.memo(SearchField);
diff --git a/src/Components/ValidationField/View/SelectField.tsx b/src/Components/ValidationField/View/SelectField.tsx
new file mode 100644
index 0000000..b923d8b
--- /dev/null
+++ b/src/Components/ValidationField/View/SelectField.tsx
@@ -0,0 +1,41 @@
+import { Form, Select } from 'antd'
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+
+const SelectField = ({ name, label, placeholder, isDisabled,option,isMulti,onChange,className, props}: any) => {
+
+ const { errorMsg, isError, t ,formik} = useFormField(name, props)
+ const SelecthandleChange = (value: { value: string; label: React.ReactNode }) => {
+ formik.setFieldValue(name, value)
+
+ };
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default React.memo(SelectField);
diff --git a/src/Components/ValidationField/View/TextArea.tsx b/src/Components/ValidationField/View/TextArea.tsx
new file mode 100644
index 0000000..62b9794
--- /dev/null
+++ b/src/Components/ValidationField/View/TextArea.tsx
@@ -0,0 +1,45 @@
+import { Form, Input } from 'antd'
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+const { TextArea } = Input;
+
+const TextAreaField = ({ name, label, placeholder, isDisabled, onChange, props,type }: any) => {
+ const { Field, formik, isError, errorMsg, t } = useFormField(name, props);
+
+
+
+ const handleChange = (e: React.ChangeEvent) => {
+ console.log('Change:', e.target.value);
+ formik.setFieldValue(name, e.target.value)
+
+ };
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default React.memo(TextAreaField);
+;
diff --git a/src/Components/ValidationField/View/Time.tsx b/src/Components/ValidationField/View/Time.tsx
new file mode 100644
index 0000000..3d3bb0c
--- /dev/null
+++ b/src/Components/ValidationField/View/Time.tsx
@@ -0,0 +1,41 @@
+import { Form, TimePicker } from 'antd'
+import React from 'react'
+import useFormField from '../../../Hooks/useFormField';
+
+const Time = ({ name, label,className,isDisabled,onChange,props }: any) => {
+
+ const { errorMsg, isError, t, formik } = useFormField(name, props)
+ const onCalendarChange = (value: any) => {
+
+ formik.setFieldValue(name, value)
+
+ };
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Time
\ No newline at end of file
diff --git a/src/Components/ValidationField/View/index.tsx b/src/Components/ValidationField/View/index.tsx
new file mode 100644
index 0000000..606e8e6
--- /dev/null
+++ b/src/Components/ValidationField/View/index.tsx
@@ -0,0 +1,22 @@
+import Time from "./Time";
+import SelectField from "./SelectField";
+import Date from "./Date";
+import DataRange from "./DataRange";
+import CheckboxField from "./CheckboxField";
+import Default from "./Default";
+import File from "./File";
+import TextAreaField from './TextArea'
+
+
+
+export {
+ Time,
+ SelectField,
+ Date,
+ DataRange,
+ CheckboxField,
+ Default,
+ File,
+ TextAreaField
+
+}
\ No newline at end of file
diff --git a/src/Components/ValidationField/index.tsx b/src/Components/ValidationField/index.tsx
new file mode 100644
index 0000000..ee84bc7
--- /dev/null
+++ b/src/Components/ValidationField/index.tsx
@@ -0,0 +1,21 @@
+import { useState } from 'react';
+import { ErrorMessage, useField, Field, useFormikContext } from 'formik';
+import { useTranslation } from 'react-i18next';
+import { FaExclamationCircle } from 'react-icons/fa';
+import Select from 'react-select';
+import { convert_data_to_select } from '../../Layout/app/Const';
+
+
+
+
+
+export {
+ useState,
+ ErrorMessage, useField, Field, useFormikContext,
+ useTranslation,
+ FaExclamationCircle,
+ Select,
+ convert_data_to_select,
+
+
+}
\ No newline at end of file
diff --git a/src/Components/ValidationField/types.ts b/src/Components/ValidationField/types.ts
new file mode 100644
index 0000000..539f2bd
--- /dev/null
+++ b/src/Components/ValidationField/types.ts
@@ -0,0 +1,132 @@
+
+// export interface ValidationFieldProps {
+// name: string;
+// type?: "text" | "Select" | "DataRange" | "Date" | "Time" | "File" | "number" | "Checkbox" | "password";
+// placeholder?: string;
+// label?: string;
+// className?: string;
+// option?: any[];
+// isMulti?: boolean;
+// isDisabled?: boolean;
+// picker?: "data" | "week" | "month" | "quarter" | "year";
+// Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM";
+// onChange?: (value: any) => void;
+// Group?: boolean
+// dir?:'ltr' | "rtl"
+// }
+
+ export interface ValidationFieldPropsText {
+ name: string;
+ type: "text";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+ }
+
+ export interface ValidationFieldPropsSelect {
+ name: string;
+ type: "Select";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?:any;
+ dir?:'ltr' | "rtl";
+ option: any[];
+ isMulti?: boolean;
+
+ }
+
+ export interface ValidationFieldPropsSearch{
+ name: string;
+ type: "Search";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl";
+ option: any[];
+ isMulti?: boolean;
+ searchBy:string;
+ loading?:boolean;
+
+ }
+ export interface ValidationFieldPropsDataRange {
+ name: string;
+ type: "DataRange";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+ Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM" | "YYYY-MM-DD HH:mm:ss.SSS";
+ }
+ export interface ValidationFieldPropsDate {
+ name: string;
+ type: "Date";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+ picker?: "data" | "week" | "month" | "quarter" | "year";
+ Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM" | "YYYY-MM-DD HH:mm:ss.SSS" | "YYYY-MM-DD HH:MM:SS";
+
+
+ }
+
+ export interface ValidationFieldPropsTime {
+ name: string;
+ type: "Time";
+ label?: string;
+ placeholder?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+
+ }
+
+ export interface ValidationFieldPropsFile {
+ name: string;
+ type: "File" | "MaltyFile";
+ placeholder?: string;
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+
+ }
+ export interface ValidationFieldPropsCheckbox {
+ name: string;
+ type: "Checkbox";
+ label?: string;
+ className?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+ Group?: boolean
+
+ }
+ export interface ValidationFieldPropstext {
+ name: string;
+ type?: "text" | "number" | "password" | "TextArea";
+ label?: string;
+ className?: string;
+ placeholder?: string;
+ isDisabled?: boolean;
+ onChange?: (value: any) => void;
+ dir?:'ltr' | "rtl"
+ Group?: boolean
+
+ }
+
+
+ export type ValidationFieldProps = ValidationFieldPropsText| ValidationFieldPropsSelect| ValidationFieldPropsDataRange| ValidationFieldPropsDate| ValidationFieldPropsTime| ValidationFieldPropsFile| ValidationFieldPropsCheckbox| ValidationFieldPropstext | ValidationFieldPropsSearch;
diff --git a/src/Components/order/OrderStatus.tsx b/src/Components/order/OrderStatus.tsx
new file mode 100644
index 0000000..79c46fb
--- /dev/null
+++ b/src/Components/order/OrderStatus.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+
+// for write later
+function OrderStatus() {
+ return (
+ OrderStatus
+ )
+}
+
+export default OrderStatus
\ No newline at end of file
diff --git a/src/Extensions/Editor/HtmlEditor.tsx b/src/Extensions/Editor/HtmlEditor.tsx
new file mode 100644
index 0000000..9d02c9b
--- /dev/null
+++ b/src/Extensions/Editor/HtmlEditor.tsx
@@ -0,0 +1,42 @@
+import React, { FC } from "react";
+import { Editor } from '@tinymce/tinymce-react';
+import { useFormikContext } from "formik";
+
+interface HtmlEditorProps {
+ langCode: number;
+ name: string;
+ editorState: string;
+}
+
+const HtmlEditor: FC = ({ langCode, name, editorState, ...props }) => {
+ const formik = useFormikContext();
+
+ const ar: boolean = langCode === 2;
+
+ return (
+ {
+ formik.setFieldValue(name, newValue)
+ }}
+ />
+ );
+}
+
+export { HtmlEditor };
\ No newline at end of file
diff --git a/src/Extensions/Editor/SingleLangEditor.tsx b/src/Extensions/Editor/SingleLangEditor.tsx
new file mode 100644
index 0000000..c8db2d6
--- /dev/null
+++ b/src/Extensions/Editor/SingleLangEditor.tsx
@@ -0,0 +1,43 @@
+import React, { FC } from "react";
+// import PropTypes from "";
+import { HtmlEditor } from "./HtmlEditor";
+import { useFormikContext } from "formik";
+import { useTranslation } from "react-i18next";
+
+interface SingleLangEditorProps {
+ langCode: number;
+ property: string;
+}
+
+const PROPERTY_TYPES: string[] = [
+ "privacy_description",
+ "conditions_description",
+ "about_us_description",
+ "product_description",
+ "auction_description"
+];
+
+const SingleLangEditor: FC = ({ langCode, property }) => {
+ const formik:any = useFormikContext();
+ const {t} = useTranslation();
+
+ const label = `${t(property)} (${t(`lang_${langCode}`)})`;
+ const fieldName = `translated_fields[${langCode}][${property}]`;
+ return (
+ <>
+ {label}
+
+ >
+ );
+};
+
+// SingleLangEditor.propTypes = {
+// langCode: PropTypes.oneOf([1, 2]).isRequired,
+// property: PropTypes.oneOf(PROPERTY_TYPES).isRequired,
+// };
+
+export default SingleLangEditor;
\ No newline at end of file
diff --git a/src/Extensions/Editor/StatusCard.tsx b/src/Extensions/Editor/StatusCard.tsx
new file mode 100644
index 0000000..25993c4
--- /dev/null
+++ b/src/Extensions/Editor/StatusCard.tsx
@@ -0,0 +1,23 @@
+import React, { FC } from "react";
+import { Card, CardBody, Spinner } from "reactstrap";
+
+interface StatusCardProps {
+ isLoading: boolean;
+ isError: boolean;
+}
+
+const StatusCard= ({ isLoading, isError }:StatusCardProps) => {
+ return (
+
+
+ {isLoading && }
+ {isError && Failed !
}
+
+
+ );
+};
+
+export default StatusCard;
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateAddModal.js b/src/Extensions/FileGenerator/generateAddModal.js
new file mode 100644
index 0000000..88f656f
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateAddModal.js
@@ -0,0 +1,65 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+let FileContiner = `
+
+import React from 'react'
+import LayoutModal from '../../Layout/Dashboard/LayoutModal'
+import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
+import { useAdd${capitalizeFirstLetter(fileName)} } from '../../api/${(fileName)}'
+import { getDataToSend, getInitialValues, getValidationSchema } from './formUtil'
+import { QueryStatusEnum } from '../../config/QueryStatus'
+import { useTranslation } from 'react-i18next'
+
+function Add${capitalizeFirstLetter(fileName)}Modal() {
+
+
+ const [t] = useTranslation()
+ const {mutate , status} = useAdd${capitalizeFirstLetter(fileName)}()
+ const handelSubmit = (values:any )=>{
+
+ const dataToSend = getDataToSend(values)
+
+ mutate(dataToSend)
+ // Submit Value
+ }
+ return (
+
+
+
+
+ )
+}
+
+export default Add${capitalizeFirstLetter(fileName)}Modal
+
+`
+fs.writeFileSync('src/Pages/'+fileName+"/"+"Add"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateApi.js b/src/Extensions/FileGenerator/generateApi.js
new file mode 100644
index 0000000..80d596e
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateApi.js
@@ -0,0 +1,40 @@
+const fs = require('fs');
+
+const fileName = process.argv[2]
+
+
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+
+let FileContiner = `
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetQuery from "./helper/useGetQuery"
+import useUpdateMutation from "./helper/useUpdateMutation"
+
+ const API = {
+ GET: "/api/admin/${fileName}",
+ ADD: "/api/admin/${fileName}/create",
+ UPDATE: "/api/admin/${fileName}/update",
+ DELETE: "/api/admin/${fileName}/delete",
+ };
+
+ const KEY = "${fileName.toUpperCase()}";
+ export const useGet${capitalizeFirstLetter(fileName)} = (params?:any) => useGetQuery(KEY, API.GET, params);
+ export const useAdd${capitalizeFirstLetter(fileName)} = () => useAddMutation(KEY, API.ADD);
+ export const useUpdate${capitalizeFirstLetter(fileName)} = () => useUpdateMutation(KEY, API.UPDATE);
+ export const useDelete${capitalizeFirstLetter(fileName)} = () =>useDeleteMutation(KEY, API.DELETE);
+`
+fs.writeFileSync('src/api/'+fileName+".ts",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateColumn.js b/src/Extensions/FileGenerator/generateColumn.js
new file mode 100644
index 0000000..c85ad21
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateColumn.js
@@ -0,0 +1,63 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+
+
+let FileContiner = `
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../Components/Ui/tables/Actions";
+
+function fnDelete(props :any ){}
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+
+ return useMemo(
+ () => [
+
+ {
+ name: t("email"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.email
+ },
+
+ {
+ name: "#",
+ sortable: false,
+ center: "true",
+ cell: (row) => (
+ row}
+ onView={()=>{}}
+ objectToEdit={row}
+ showEdit={true}
+ // showDelete={false}
+ onDelete={() => fnDelete({ id: row.id })}
+ />
+ ),
+ },
+ ],
+ [t]
+ );
+};
+
+export default useTableColumns;
+
+`
+fs.writeFileSync('src/Pages/'+fileName+"/useTableColumns"+".tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
diff --git a/src/Extensions/FileGenerator/generateDashboard.js b/src/Extensions/FileGenerator/generateDashboard.js
new file mode 100644
index 0000000..f291fd9
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateDashboard.js
@@ -0,0 +1,30 @@
+const { exec } = require('child_process');
+
+
+const fileName = process.argv[2]
+
+
+const CreateApi = `node src/Extensions/FileGenerator/generateApi.js ${fileName}`
+const CreatePage = `node src/Extensions/FileGenerator/generatePage.js ${fileName}`
+const CreateColumn = `node src/Extensions/FileGenerator/generateColumn.js ${fileName}`
+const CreateformUtil= `node src/Extensions/FileGenerator/generateformUtils.js ${fileName}`
+const CreateAddModal= `node src/Extensions/FileGenerator/generateAddModal.js ${fileName}`
+const CreateEditModal= `node src/Extensions/FileGenerator/generateEditModal.js ${fileName}`
+const CreateForm= `node src/Extensions/FileGenerator/generateForm.js ${fileName}`
+
+
+
+const RunCommand = async()=>{
+
+ exec(CreatePage)
+ exec(CreateApi)
+ setTimeout(()=>{},100)
+ exec(CreateColumn)
+ exec(CreateformUtil)
+ exec(CreateAddModal)
+ exec(CreateEditModal)
+ exec(CreateForm)
+
+}
+
+RunCommand()
diff --git a/src/Extensions/FileGenerator/generateEditModal.js b/src/Extensions/FileGenerator/generateEditModal.js
new file mode 100644
index 0000000..0171481
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateEditModal.js
@@ -0,0 +1,47 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+let FileContiner = `
+import React from 'react'
+import LayoutModal from '../../Layout/Dashboard/LayoutModal'
+import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
+import { getInitialValues, getValidationSchema } from './formUtil'
+import { usePageState } from '../../lib/state mangment/LayoutPagestate'
+
+function Edit${capitalizeFirstLetter(fileName)}Modal() {
+ const {objectToEdit} = usePageState()
+ return (
+ { }}
+ headerText='Edit Modal'
+ getValidationSchema={getValidationSchema(objectToEdit)}>
+
+
+ )
+}
+
+export default Edit${capitalizeFirstLetter(fileName)}Modal
+`
+fs.writeFileSync('src/Pages/'+fileName+"/"+"Edit"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateForm.js b/src/Extensions/FileGenerator/generateForm.js
new file mode 100644
index 0000000..3558bd6
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateForm.js
@@ -0,0 +1,66 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+let FileContiner = `
+import React from 'react'
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../Components/ValidationField/ValidationField';
+import { FakeSelectData } from '../../Layout/app/Const';
+import { useFormikContext } from 'formik';
+
+import { DatePicker } from 'antd';
+
+function Form${capitalizeFirstLetter(fileName)}() {
+ const formik = useFormikContext();
+
+
+
+ return (
+
+
+ // name from form utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form${capitalizeFirstLetter(fileName)}
+
+
+`
+fs.writeFileSync('src/Pages/'+fileName+'/Form'+ capitalizeFirstLetter(fileName)+".tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateModel.js b/src/Extensions/FileGenerator/generateModel.js
new file mode 100644
index 0000000..442421c
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateModel.js
@@ -0,0 +1,64 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+let FileContiner = `
+
+import React from 'react'
+import LayoutModal from '../../Layout/Dashboard/LayoutModal'
+import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
+import { useAdd${capitalizeFirstLetter(fileName)} } from '../../api/${(fileName)}'
+import { getDataToSend, getInitialValues, getValidationSchema } from './formUtil'
+import { QueryStatusEnum } from '../../config/QueryStatus'
+import { useTranslation } from 'react-i18next'
+
+function Add${capitalizeFirstLetter(fileName)}Modal() {
+
+
+ const [t] = useTranslation()
+ const {mutate , status} = useAdd${capitalizeFirstLetter(fileName)}()
+ const handelSubmit = (values:any )=>{
+
+ const dataToSend = getDataToSend(values)
+
+ mutate(dataToSend)
+ // Submit Value
+ }
+ return (
+
+
+
+
+ )
+}
+
+export default Add${capitalizeFirstLetter(fileName)}Modal
+
+`
+fs.writeFileSync('src/Pages/'+fileName+"/"+"Add"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generatePage.js b/src/Extensions/FileGenerator/generatePage.js
new file mode 100644
index 0000000..f200971
--- /dev/null
+++ b/src/Extensions/FileGenerator/generatePage.js
@@ -0,0 +1,67 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+const folderPath = 'src/Pages/'+fileName;
+
+
+if (!fs.existsSync(folderPath)) {
+ fs.mkdirSync(folderPath, { recursive: true });
+}
+
+let FileContiner = `
+import React from 'react'
+import DashBody from '../../Layout/Dashboard/DashBody'
+import DashHeader from '../../Layout/Dashboard/DashHeader'
+import LyTable from '../../Layout/Dashboard/LyTable'
+import useTableColumns from './useTableColumns'
+import { useGet${capitalizeFirstLetter(fileName)}} from '../../api/${fileName}'
+import { QueryStatusEnum } from '../../config/QueryStatus'
+import Edit${capitalizeFirstLetter(fileName)}Modal from './Edit${capitalizeFirstLetter(fileName)}Modal'
+import Add${capitalizeFirstLetter(fileName)}Modal from './Add${capitalizeFirstLetter(fileName)}Modal'
+
+function ${capitalizeFirstLetter(fileName)}Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGet${capitalizeFirstLetter(fileName)}()
+
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default ${capitalizeFirstLetter(fileName)}Page
+
+`
+
+fs.writeFileSync('src/Pages/'+fileName+"/"+capitalizeFirstLetter(fileName)+"Page.tsx",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Extensions/FileGenerator/generateformUtils.js b/src/Extensions/FileGenerator/generateformUtils.js
new file mode 100644
index 0000000..f608f43
--- /dev/null
+++ b/src/Extensions/FileGenerator/generateformUtils.js
@@ -0,0 +1,73 @@
+const fs = require('fs');
+
+// Get the file name from the command line arguments
+const fileName = process.argv[2];
+
+// Check if a file name is provided
+if (!fileName) {
+ console.error('Please provide a file name.');
+ process.exit(1);
+}
+
+let FileContiner = `
+import * as Yup from "yup";
+import { buildFormData } from "../../api/helper/buildFormData";
+
+interface formUtilCommon {
+ name:string,
+ email:string
+}
+
+interface ObjectToEdit extends formUtilCommon {
+
+ id?:number,
+
+}
+
+interface InitialValues extends ObjectToEdit {
+
+}
+interface ValidateSchema extends formUtilCommon{
+
+}
+
+export const getInitialValues = (objectToEdit: ObjectToEdit | null = null): InitialValues => {
+
+
+ return {
+ id:objectToEdit?.id?? 0 ,
+ name:objectToEdit?.name ?? "",
+ email:objectToEdit?.email?? ""
+ }
+
+
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // validate input
+ return Yup.object().shape({
+ name:Yup.string().required('required'),
+ email:Yup.string().required("required")
+ });
+};
+
+export const getDataToSend = (values: any): FormData => {
+ const data = { ...values };
+
+
+ const formData = new FormData();
+ buildFormData(formData, data);
+ return formData;
+};
+
+`
+fs.writeFileSync('src/Pages/'+fileName+"/"+"formUtil.ts",
+FileContiner
+);
+
+console.log(`File "${fileName}" generated successfully.`);
+
+
+function capitalizeFirstLetter(word) {
+ return (word).charAt(0).toUpperCase() + (word).slice(1);
+}
\ No newline at end of file
diff --git a/src/Hooks/WithDrawer.tsx b/src/Hooks/WithDrawer.tsx
new file mode 100644
index 0000000..4373fe1
--- /dev/null
+++ b/src/Hooks/WithDrawer.tsx
@@ -0,0 +1,45 @@
+import React, { useState, ReactNode } from 'react';
+import type { DrawerProps } from 'antd';
+import { Drawer, Space } from 'antd';
+
+interface WithDrawerProps {
+ button: React.ReactNode;
+ children: ReactNode;
+ title:string;
+ className?:string,
+ iopen?:boolean,
+ setOpen:any
+}
+
+const WithDrawer: React.FC = ({ children,title ="Basic Drawer",className ,setOpen, iopen }) => {
+ const [placement, setPlacement] = useState('right');
+
+
+
+ return (
+ <>
+ setOpen(false)}
+ open={iopen}
+ key={placement}
+ >
+
+ {children}
+
+
+
+ >
+ );
+};
+
+export default WithDrawer;
+
+
+// Open}
+// >
+// {/* Your content goes here */}
+//
\ No newline at end of file
diff --git a/src/Hooks/imageUrlToFile.tsx b/src/Hooks/imageUrlToFile.tsx
new file mode 100644
index 0000000..255055b
--- /dev/null
+++ b/src/Hooks/imageUrlToFile.tsx
@@ -0,0 +1,13 @@
+export async function fetchImage(imageUrl:any) {
+ try {
+ const response = await fetch(imageUrl);
+ if (!response.ok) {
+ throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`);
+ }
+ const blob = await response.blob();
+ return new File([blob], 'image.png', { type: 'image/png' });
+ } catch (error) {
+ console.error('Error fetching image:', error);
+ return null;
+ }
+ }
diff --git a/src/Hooks/isEmpty.tsx b/src/Hooks/isEmpty.tsx
new file mode 100644
index 0000000..e20a5fe
--- /dev/null
+++ b/src/Hooks/isEmpty.tsx
@@ -0,0 +1,3 @@
+export const isEmpty = (Type:any) => {
+ return !Type || (Array.isArray(Type) && Type.length === 0);
+ };
\ No newline at end of file
diff --git a/src/Hooks/useChangeLanguage.tsx b/src/Hooks/useChangeLanguage.tsx
new file mode 100644
index 0000000..62c9da3
--- /dev/null
+++ b/src/Hooks/useChangeLanguage.tsx
@@ -0,0 +1,62 @@
+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';
+
+
+let language = localStorage.getItem('language') ?? 'en';
+
+i18n.use(initReactI18next).init({
+ resources: {
+ en: {
+ translation: translationEN
+ },
+ ar: {
+ translation: translationAR
+ }
+ },
+ lng: language ?? "en",
+ interpolation: {
+ escapeValue: false
+ }
+ });
+
+// console.log(navigator.language,"navigator.language");
+
+export function useLanguage() {
+ useEffect(() => {
+ changeLanguage(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');
+ }
+}
+
+export function useLanguageMenu() {
+ const { t } = useTranslation();
+
+ const languageOptions = [
+ { code: 'ar', icon: '/Layout/Ar.svg', label: t('Arabic') },
+ { code: 'en', icon: '/Layout/En.svg', label: t('English') },
+ ];
+
+ return { languageOptions };
+}
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..2c9980d
--- /dev/null
+++ b/src/Hooks/useFormatToSelect.tsx
@@ -0,0 +1,16 @@
+const useFormatToSelect = (Data : any) => {
+ const format = (data :any) => {
+ if (!data) return [];
+ const language = localStorage.getItem("language") ?? "en";
+
+ return data.map((item :any) => ({
+ value: item?.id,
+ label: item?.name[language],
+ }));
+ };
+
+ return format(Data);
+ };
+
+ export default useFormatToSelect;
+
\ No newline at end of file
diff --git a/src/Hooks/useImageError.tsx b/src/Hooks/useImageError.tsx
new file mode 100644
index 0000000..db0d853
--- /dev/null
+++ b/src/Hooks/useImageError.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+const useImageError = ({currentTarget}:any) => {
+ const ErrorImage = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/65/No-Image-Placeholder.svg/832px-No-Image-Placeholder.svg.png"
+ currentTarget.onerror = null;
+ currentTarget.src=`${ErrorImage}`;
+}
+
+export default useImageError
\ No newline at end of file
diff --git a/src/Hooks/useLoadingState.tsx b/src/Hooks/useLoadingState.tsx
new file mode 100644
index 0000000..dfda80d
--- /dev/null
+++ b/src/Hooks/useLoadingState.tsx
@@ -0,0 +1,21 @@
+import { useState, useEffect } from 'react';
+
+function useLoadingState(initialValue: boolean, duration: number): [boolean, () => void] {
+ const [loading, setLoading] = useState(initialValue);
+
+ useEffect(() => {
+ const timeoutId = setTimeout(() => {
+ setLoading(false);
+ }, duration);
+
+ return () => clearTimeout(timeoutId);
+ }, [duration]);
+
+ const resetLoading = () => {
+ setLoading(true);
+ };
+
+ return [loading, resetLoading];
+}
+
+export default useLoadingState;
diff --git a/src/Hooks/useNavigateOnSuccess.ts b/src/Hooks/useNavigateOnSuccess.ts
new file mode 100644
index 0000000..2b012c3
--- /dev/null
+++ b/src/Hooks/useNavigateOnSuccess.ts
@@ -0,0 +1,20 @@
+import React, { useEffect } from 'react'
+import { useNavigate } from 'react-router-dom'
+
+
+function useNavigateOnSuccess(isSuccess :boolean , to_path:string , callbackAfterSuccess?:any) {
+
+ const navigate = useNavigate()
+ useEffect(()=>{
+
+ if(isSuccess){
+ if (typeof callbackAfterSuccess === 'function') {
+ callbackAfterSuccess()
+ }
+ navigate(to_path )
+ }
+ },[isSuccess])
+
+}
+
+export default useNavigateOnSuccess
\ No newline at end of file
diff --git a/src/Hooks/usePagination.tsx b/src/Hooks/usePagination.tsx
new file mode 100644
index 0000000..5008afe
--- /dev/null
+++ b/src/Hooks/usePagination.tsx
@@ -0,0 +1,38 @@
+import { Pagination } from "antd";
+import { useTranslation } from "react-i18next";
+import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
+
+export const PaginationBody = ({ data }: any) => {
+ const navigate = useNavigate();
+ const location = useLocation();
+ const pagination = location?.search || '';
+ const currentPage = parseInt(new URLSearchParams(location.search).get("page") || "1", 10);
+ const pageSize = parseInt(new URLSearchParams(location.search).get("per_page") || "15", 10);
+
+ const [searchParams] = useSearchParams()
+ const onChange = (page: number, pageSize?: number) => {
+ navigate(`?page=${page}&per_page=${pageSize || data?.per_page}`);
+ };
+
+ const onShowSizeChange = (current: number, pageSize: number) => {
+ navigate(`?page=${current}&per_page=${pageSize}`);
+ };
+ const [t] = useTranslation()
+
+ return (
+ `${t(`Total`)} ${total} ${t(`items`)}`}
+ pageSize={pageSize}
+ pageSizeOptions={[6, 15, 22, 30]}
+ defaultCurrent={currentPage}
+ current={currentPage}
+ onChange={onChange}
+ onShowSizeChange={onShowSizeChange}
+ // showQuickJumper
+ showSizeChanger
+
+ />
+ );
+};
diff --git a/src/Hooks/useWindowSize.tsx b/src/Hooks/useWindowSize.tsx
new file mode 100644
index 0000000..853fdb8
--- /dev/null
+++ b/src/Hooks/useWindowSize.tsx
@@ -0,0 +1,18 @@
+import { useState } from "react";
+import { useEventListener } from "./useEventListener";
+
+export const useWindowSize = () => {
+ const [windowSize, setWindowSize] = useState({
+ width: window.innerWidth,
+ height: window.innerHeight,
+ });
+
+ useEventListener("resize", () => {
+ setWindowSize({
+ width: window.innerWidth,
+ height: window.innerHeight,
+ });
+ });
+
+ return windowSize;
+};
diff --git a/src/Layout/Dashboard/AddButton/AddButton.tsx b/src/Layout/Dashboard/AddButton/AddButton.tsx
new file mode 100644
index 0000000..d6d8cec
--- /dev/null
+++ b/src/Layout/Dashboard/AddButton/AddButton.tsx
@@ -0,0 +1,33 @@
+import React from 'react'
+import './Add_Button.scss'
+import { useTranslation } from 'react-i18next'
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate'
+
+
+
+const AddButton = (props :any) => {
+ const [t] = useTranslation();
+
+
+ return (
+
+
+
+
+ )
+}
+
+export default AddButton
\ No newline at end of file
diff --git a/src/Layout/Dashboard/AddButton/AddButtonLayout.tsx b/src/Layout/Dashboard/AddButton/AddButtonLayout.tsx
new file mode 100644
index 0000000..d796bae
--- /dev/null
+++ b/src/Layout/Dashboard/AddButton/AddButtonLayout.tsx
@@ -0,0 +1,41 @@
+import React from 'react'
+import './Add_Button.scss'
+import { useTranslation } from 'react-i18next'
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate'
+
+
+
+const AddButtonLayout = ({haveAddModal}:any) => {
+ const { setIsOpenAddModel , setObjectToEdit } = usePageState()
+ const [t] = useTranslation();
+
+
+ return (
+ {
+ if(haveAddModal){
+
+ setIsOpenAddModel()
+ }
+ setObjectToEdit(null)
+
+ }}>
+
+
+
+ )
+}
+
+export default AddButtonLayout
\ No newline at end of file
diff --git a/src/Layout/Dashboard/AddButton/Add_Button.scss b/src/Layout/Dashboard/AddButton/Add_Button.scss
new file mode 100644
index 0000000..fc7a862
--- /dev/null
+++ b/src/Layout/Dashboard/AddButton/Add_Button.scss
@@ -0,0 +1,77 @@
+.Add_Button{
+ button {
+ border: 2px solid var(--primary);
+ background-color: var(--primary);
+ border-radius: 0.5vw;
+ height: 40px;
+ width: 70px;
+ font-size: 1vw ;
+ display: flex; justify-content: center; align-items: center;
+ box-shadow: 2px 2px 7px 0 var(--primary);
+ }
+ button span {
+ display: flex;
+ align-items: center;
+ color: var(--bg);
+ font-weight: normal;
+ font-size: 14px;
+ }
+
+ button:hover {
+ background-color:var(--primary);
+ }
+}
+
+@media screen and (max-width: 700px) {
+ .Add_Button{
+ button{
+ font-size: 2vw !important;
+ }
+ }
+}
+@media screen and (max-width: 470px) {
+ .Add_Button{
+ button{
+ font-size: 3vw !important;
+ }
+ }
+}
+
+ .Add_Button_notification{
+ button {
+ border: 2px solid var(--primary);
+ background-color: var(--primary);
+ border-radius: 0.5vw;
+ height: 40px;
+ width: 180px;
+ font-size: 1vw ;
+ display: flex; justify-content: center; align-items: center;
+ box-shadow: 2px 2px 7px 0 var(--primary);
+ }
+ button span {
+ display: flex;
+ align-items: center;
+ color: var(--bg);
+ font-weight: normal;
+ font-size: 14px;
+ }
+
+ button:hover {
+ background-color:var(--primary);
+ }
+ }
+
+ @media screen and (max-width: 700px) {
+ .Add_Button_notification{
+ button{
+ font-size: 2vw !important;
+ }
+ }
+ }
+ @media screen and (max-width: 470px) {
+ .Add_Button_notification{
+ button{
+ font-size: 3vw !important;
+ }
+ }
+ }
diff --git a/src/Layout/Dashboard/DashBody.tsx b/src/Layout/Dashboard/DashBody.tsx
new file mode 100644
index 0000000..8f2f449
--- /dev/null
+++ b/src/Layout/Dashboard/DashBody.tsx
@@ -0,0 +1,32 @@
+import { Spinner } from "reactstrap"
+import { QueryStatusEnum } from "../../config/QueryStatus"
+import LoadingPage from "../app/LoadingPage"
+import { useTranslation } from "react-i18next"
+import { BsEmojiFrown } from "react-icons/bs";
+import ErrorPage from "../app/ErrorPage";
+
+
+const DashBody = ({ children , status }: { children: React.ReactNode ,status?:QueryStatusEnum }) => {
+ const {t} = useTranslation();
+
+ // Add You Custom Loadaing Page
+ if(status === QueryStatusEnum.LOADING){
+
+ return
+ }
+
+ // Add Your Custom Error Page
+ if(status === QueryStatusEnum.ERROR){
+ return (
+
+ )
+ }
+
+ return (
+
+ { children }
+
+ )
+}
+
+export default DashBody
diff --git a/src/Layout/Dashboard/DashHeader.tsx b/src/Layout/Dashboard/DashHeader.tsx
new file mode 100644
index 0000000..a71852d
--- /dev/null
+++ b/src/Layout/Dashboard/DashHeader.tsx
@@ -0,0 +1,27 @@
+import React from "react";
+import AddButtonLayout from "./AddButton/AddButtonLayout";
+import { useTranslation } from "react-i18next";
+
+interface DashHeaderProp {
+ title: string;
+ children?: React.ReactNode;
+ showAddButton?: boolean;
+ haveAddModal?:boolean
+}
+const DashHeader = ({
+ children,
+ title,
+ haveAddModal= true ,
+ showAddButton = true,
+}: DashHeaderProp) => {
+ const [t] = useTranslation();
+ return (
+
+
{t(`${title}`)}
+ {children}
+ {showAddButton &&
}
+
+ );
+};
+
+export default DashHeader;
diff --git a/src/Layout/Dashboard/FormPage.tsx b/src/Layout/Dashboard/FormPage.tsx
new file mode 100644
index 0000000..befc606
--- /dev/null
+++ b/src/Layout/Dashboard/FormPage.tsx
@@ -0,0 +1,42 @@
+import { Formik, Form } from 'formik';
+import React, { ReactNode } from 'react';
+import { Button } from "reactstrap";
+import * as Yup from 'yup';
+
+interface FormValues {
+ [key: string]: any;
+}
+
+interface FormPageProps {
+ handleSubmit: (values: any) => void
+ initialValues: FormValues;
+ validationSchema: any;
+ title?: string;
+ children: ReactNode;
+}
+
+const FormPage: React.FC = ({ children, handleSubmit, initialValues, validationSchema, title = "Edit Item" }) => {
+ return (
+ <>
+ {title}
+
+
+ {formik => (
+
+ )}
+
+
+ >
+ );
+};
+
+export default FormPage;
diff --git a/src/Layout/Dashboard/FormikForm.tsx b/src/Layout/Dashboard/FormikForm.tsx
new file mode 100644
index 0000000..9e42628
--- /dev/null
+++ b/src/Layout/Dashboard/FormikForm.tsx
@@ -0,0 +1,67 @@
+import { Formik, Form } from 'formik';
+import React, { ReactNode } from 'react';
+import { useTranslation } from 'react-i18next';
+import { Button } from "reactstrap";
+import * as Yup from 'yup';
+
+interface FormValues {
+ [key: string]: any;
+}
+
+interface FormikFormProps {
+ handleSubmit: (values: any) => void
+ initialValues: FormValues;
+ validationSchema: any;
+ title?: string;
+ children: ReactNode;
+ ButtonName?:string
+}
+const FormikForm: React.FC = ({ children, handleSubmit, initialValues, validationSchema, title = "Add New Item" ,ButtonName="إضافة"}) => {
+ const [t]= useTranslation()
+
+ return (
+ <>
+
+ {formik => (
+
+ )}
+
+ >
+ );
+};
+
+export default FormikForm;
+
+
+
+{/* {
+
+}}
+initialValues={() => {
+ return {
+ id: null,
+ name: "",
+
+ }
+}}
+validationSchema={() => {
+ return Yup.object().shape({
+ name: Yup.string().required('required'),
+
+ });
+}}
+
+>
+
+ */}
\ No newline at end of file
diff --git a/src/Layout/Dashboard/LayoutModal.tsx b/src/Layout/Dashboard/LayoutModal.tsx
new file mode 100644
index 0000000..926e7f0
--- /dev/null
+++ b/src/Layout/Dashboard/LayoutModal.tsx
@@ -0,0 +1,77 @@
+import { Form, Formik } from 'formik'
+import React, { useEffect } from 'react'
+import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'
+import { usePageState } from '../../lib/state mangment/LayoutPagestate'
+import { useTranslation } from 'react-i18next';
+import { LoadingButton } from '../../Components/Ui/LoadingButton';
+import { QueryStatusEnum } from '../../config/QueryStatus';
+
+interface LayoutModalProps {
+ isAddModal: boolean;
+ headerText: string;
+ handleSubmit: (values: any) => void;
+ getInitialValues: any;
+ getValidationSchema: any;
+ children: React.ReactNode;
+ status?:QueryStatusEnum
+}
+function LayoutModal({isAddModal , headerText , handleSubmit =()=>{} , getInitialValues , getValidationSchema,status ,children}:LayoutModalProps) {
+
+
+
+ const {isOpenAddModel ,setIsOpenAddModel , setIsOpenEditModel ,isOpenEditModel , objectToEdit , CloseAllModal} = usePageState(state => state)
+
+
+ useEffect(()=>{
+ if(status === QueryStatusEnum.SUCCESS){
+ CloseAllModal()
+ }
+ },[status , CloseAllModal])
+
+ const [t] = useTranslation()
+ return (
+
+ isAddModal ?setIsOpenAddModel() : setIsOpenEditModel()} >
+ {t(headerText)}
+
+ {
+
+ (( objectToEdit != null && isOpenEditModel) || isOpenAddModel) &&
+
+
+ {(formik) => (
+
+ )}
+
+ }
+
+
+ )
+}
+
+export default LayoutModal
\ No newline at end of file
diff --git a/src/Layout/Dashboard/LyTable.tsx b/src/Layout/Dashboard/LyTable.tsx
new file mode 100644
index 0000000..be96f09
--- /dev/null
+++ b/src/Layout/Dashboard/LyTable.tsx
@@ -0,0 +1,39 @@
+
+import DataTable from 'react-data-table-component';
+import { Card, CardBody, Spinner } from 'reactstrap';
+import { PaginationBody } from '../../Hooks/usePagination';
+import { useTranslation } from 'react-i18next';
+
+const LyTable = (props?: any) => {
+ const {t} = useTranslation();
+
+ return (
+
+
+
+ {t("no_records")}}
+ noHeader
+ pagination
+ progressComponent={}
+
+ {...(props.is_pagination && {
+ paginationServer: true,
+ paginationComponent: () =>
+ })}
+
+ {...props}
+ />
+
+
+
+
+
+ )
+}
+
+
+export default LyTable
\ No newline at end of file
diff --git a/src/Layout/Dashboard/PageStructure.tsx b/src/Layout/Dashboard/PageStructure.tsx
new file mode 100644
index 0000000..570254d
--- /dev/null
+++ b/src/Layout/Dashboard/PageStructure.tsx
@@ -0,0 +1,36 @@
+import React, { FC } from "react";
+import StatusCard from "../../Extensions/Editor/StatusCard";
+import { Card, CardHeader, CardBody, CardTitle } from "reactstrap";
+import { useTranslation } from "react-i18next";
+
+interface PageStructureProps {
+ title?: string;
+ isLoading: boolean;
+ isError: boolean;
+ data?: any;
+ children:any
+}
+
+const PageStructure: FC = ({
+ title,
+ isLoading,
+ isError,
+ data,
+ children,
+}) => {
+ const {t} = useTranslation();
+
+ if (!data) return ;
+ return (
+
+ {title && (
+
+ {t(title)}
+
+ )}
+ {children}
+
+ );
+};
+
+export default PageStructure;
\ No newline at end of file
diff --git a/src/Layout/Dashboard/SearchField.tsx b/src/Layout/Dashboard/SearchField.tsx
new file mode 100644
index 0000000..02b03d2
--- /dev/null
+++ b/src/Layout/Dashboard/SearchField.tsx
@@ -0,0 +1,56 @@
+import { Input } from 'antd';
+import { SearchProps } from 'antd/es/input'
+import { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';
+const { Search } = Input;
+
+const SearchField = ({ searchBy }: any) => {
+ const navigate = useNavigate()
+ const [searchParams,] = useSearchParams();
+ const location = useLocation()
+ const { t } = useTranslation();
+
+
+ const [searchValue, setSearchValue] = useState(searchParams.get(searchBy ?? "search") || "");
+
+ const onSearch: SearchProps['onSearch'] = (value, _e, info) => {
+ if (value || value !== "") {
+ navigate(`${location?.pathname}?${searchBy ?? "search"}=${value}`);
+ } else {
+ const params = new URLSearchParams(location.search);
+ params.delete(searchBy ?? "search");
+ navigate(`${location.pathname}?${params.toString()}`);
+ }
+ }
+
+ const onChange = (e: any) => {
+ const value = e.target.value
+ setSearchValue(e.target.value);
+ if (value === "") {
+ const params = new URLSearchParams(location.search);
+ params.delete(searchBy ?? "search");
+ navigate(`${location.pathname}?${params.toString()}`);
+ }
+ }
+
+
+ return (
+
+
+
+
+ )
+}
+
+export default SearchField
\ No newline at end of file
diff --git a/src/Layout/Dashboard/SelectField.tsx b/src/Layout/Dashboard/SelectField.tsx
new file mode 100644
index 0000000..62bc44f
--- /dev/null
+++ b/src/Layout/Dashboard/SelectField.tsx
@@ -0,0 +1,46 @@
+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(selectBy) || '');
+ }, [location.search, selectBy,setSearchQuery]);
+
+
+ const handleSelectChange = (value: any) => {
+ if (value) {
+ console.log(`${location.pathname}?${selectBy}=${value}`);
+ navigate(`${location.pathname}?${selectBy}=${value}`);
+ }
+ }
+ const handleonClear = () => {
+ navigate(`${location.pathname}`);
+
+ }
+
+ 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..407862e
--- /dev/null
+++ b/src/Layout/Dashboard/ViewPage.tsx
@@ -0,0 +1,88 @@
+import React from "react";
+import { Card, CardHeader, CardTitle, CardBody, Button } from "reactstrap";
+import { Formik, Form } from "formik";
+import { LoadingButton } from "../../Components/Ui/LoadingButton";
+import ProgressBar from "../../Components/Ui/ProgressBar";
+import { useLocation, useNavigate } from "react-router-dom";
+import { usePageState } from "../../lib/state mangment/LayoutPagestate";
+import { useTranslation } from "react-i18next";
+
+type TViewPage ={
+ children: React.ReactNode,
+ getInitialValues:any,
+ getValidationSchema:any,
+ getDataToSend:any,
+ handleSubmit:any,
+ // BarStatus:any,
+ IsloadingButton:boolean
+}
+
+const ViewPage: React.FC= ({children,getInitialValues, getValidationSchema,handleSubmit,IsloadingButton})=> {
+
+ const {objectToEdit} = usePageState()
+ const {t} = useTranslation();
+ const navigate = useNavigate();
+ // console.log(BarStatus);
+
+ const location = useLocation();
+
+
+
+ const navigateToParent = () => {
+ // // Get the current path
+ // const currentPath = window.location.pathname;
+ // // Find the index of the second '/' in the current path
+ // const secondSlashIndex = currentPath.indexOf('/', 1);
+ // // Extract the parent path
+ // const parentPath = secondSlashIndex !== -1 ? currentPath.substring(0, secondSlashIndex) : currentPath;
+ // // Navigate to the parent path
+ // navigate(parentPath);
+ navigate(-1)
+ };
+
+ return (
+
+
+
+ {t("View_information")}
+
+
+
+
+ {
+
+ {(formik) => (
+
+ )}
+
+ }
+
+
+
+ );
+};
+
+
+export default ViewPage;
diff --git a/src/Layout/Dashboard/useCloseModal.ts b/src/Layout/Dashboard/useCloseModal.ts
new file mode 100644
index 0000000..993685d
--- /dev/null
+++ b/src/Layout/Dashboard/useCloseModal.ts
@@ -0,0 +1,18 @@
+import React, { useEffect } from 'react'
+import { usePageState } from '../../lib/state mangment/LayoutPagestate'
+
+function useCloseModal(statusClose:any) {
+
+ const {CloseAllModal} = usePageState()
+
+ useEffect(()=>{
+
+ if(statusClose){
+ CloseAllModal()
+ }
+ },[statusClose , CloseAllModal])
+
+ return true
+}
+
+export default useCloseModal
\ No newline at end of file
diff --git a/src/Layout/app/Const.tsx b/src/Layout/app/Const.tsx
new file mode 100644
index 0000000..bb3c0cb
--- /dev/null
+++ b/src/Layout/app/Const.tsx
@@ -0,0 +1,48 @@
+export const SideBarLogoUrl = "../Layout/KarimLogo.svg";
+export const UserImageURL = "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMsaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjUtYzAxNCA3OS4xNTE0ODEsIDIwMTMvMDMvMTMtMTI6MDk6MTUgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4RDI0Q0Q2RjcxQ0ExMUU1QjA2Q0JBMTlGNjJDRUVCMyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4RDI0Q0Q3MDcxQ0ExMUU1QjA2Q0JBMTlGNjJDRUVCMyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjhEMjRDRDZENzFDQTExRTVCMDZDQkExOUY2MkNFRUIzIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjhEMjRDRDZFNzFDQTExRTVCMDZDQkExOUY2MkNFRUIzIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgB9AH0AwERAAIRAQMRAf/EAHwAAQACAwEBAAAAAAAAAAAAAAABBgMEBQcCAQEAAAAAAAAAAAAAAAAAAAAAEAEAAgECAwQIBAIHCQEAAAAAAQIDEQQhBQYxQVESYXGBkSIyQhOxwVIjoRTRYjNTJBU14XKCkrLiQ4NUFhEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A9cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAJAAAABAJAAAAAABAJAAAAAAAAAAAAABAJAABAJAAAAAAAAAAAAAAAAAAAAAAAAAAABAJAAAAAAAAAAAAAABAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAJAAAAAAAAAAAAAABAJA1AAAAAAAAAAAAAAAAAAAAAAABAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB948OXJPlx0m8z3RGoN/B07zbNETGCaRP65iv4g3cXR29tGuTNjp6I1mfwBsV6M/XutPDSmv5wCf/xeP/65/wCT/uBjt0Zk4+Tc1nw1rMA1s3SXM6fJNMnqnT8dAaG45RzLb/2mC0R+qI1j3wDTmJidJjQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAmImZ0iNZ8IB1Nl05zHc+W00+1jn6r8OHqBYNn0ry/DpbLrntw+bhHD0QDq4dvgw18uLHWkf1YiAZAAAAAAAau55XsNzExlw1mZ+qI0n3wDib7pCsxNtnk0ntjHfs9WoOBu+W73aTpnxTWPHtj3g1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbvLuUbzfX/arpjifiyT2QC2ct6f2WymL6fdzfrt+UA6gAAAAAAAAAAAPnJix5aTTJWLVnhMTxBXOZ9J0ms5NjOlv7qez2SCtZsGXBknHlrNL14TEg+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd7kvTd9zEZ91rXD21p32BbMWLHixxjx1ilKxpEQD7AAAAAAAAAAAAAABpcy5Ttd/j8uWumSPlyR2wCl8y5Zudhm+3ljWs/JeOyYBpgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs3T/T1ZrTebyuuvxYsM+HdNtf4As4AAAAAAAAAAAAAAAAAMO72mDd4LYc9fNS3vifGAUfnHKMvLtx5Z1thvxxZPGPCfTANAAAAAAAAAAAAAAAAAAAAAAAAAAEAkAAAAAAAAAAAAAFg6b5H9+0bzcV/arOuKs/VMd/qBbQAAAAAAAAAAAAAAAAAAAYN7s8O8218GWNa27J74numAUPmXL82x3VsOSOHbS3daviDVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0OS8stv93FJ4YqfFln0eAL3jx0x4648cRWlY0rEeAPoAAAAAAAAAAAAAAAAAAAAHO51yqm/2sxpEZ6ccd/yBRL0tS81tGlqzpMemAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACa1ta0VrGtrTpER3yC+cj5fGy2NKTH7t/iyT6Z7gdAAAAAAAAAAAAAAAAAAAAAAAFT6r5ZOPNG8x1+C/DJp3T4+0FeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2ultjGffTmvGtMMax4ebuBcwAAAAAAAAAAAAAAAAAAAAAAAYd5tqbnbZMN41reJj2g87zYrYst8duFqTMTHqB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvXT2zjbctx6xHnyfHaY9PYDpgAAAAAAAAAAAAAAAAAAAAAAAAp/VuzjFva56xEVzRx0/VAOEAAAAAAAAAAAAAAAAAAAAAACASACASAAAAAAADY5ft53G9w4YjXz2iJ9QPRK1itYrHZEaR7ASAAAAAAAAAAAAAAAAAAAAAAAADk9T7X73K72iNbYpi8ervBSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdvpLBGTmU5J/wDFSZ9s8AXIAAAAAAAAAAAAAAAAAAAAAAAAAGPcYozYMmKey9Zr74B5vkr5L2r+mZj3AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFp6NxR9vcZe/WtY/EFkAAAAAAAAAAAAAAAAAAAAAAAAAAB57zfFGLmW4pHZF50BqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuPSFJjl17d1sk6eyIB3AAAAAAAAAAAAAAAAAAAAAAAAAAAUbqWs15xm17/LPvgHLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABc+kv9K/8AZb8IB2gAAAAAAAAAAAAAAAAAAAAAAAAAAUjqn/Wcv+7T/pgHJAAAAAAAAAAAAAAAAAAAAAAAAAAABAJAAAABcOkLzPL8ldflyTw9cA7oAAAAAAAAAAAAAAAAAAAAAAAAAAKL1Jebc4z8ddNI90A5gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALP0Zl+HcYfVaPwBZgAAAAAAAAAAAAAAAAAAAAAAAAAAeec1y/e5juMnda86A1QAQCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdnpTcfa5n5J7MtZr7uILoAAAAAAAAAAAAAAAAAAAAAAAAADFus0Ydtlyz9FZn3QDzi9vNe1vGZn3ggEAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGbZZ5wbrFmidJpaJ1B6LjvW9K3rOsWiJifWD6AAAAAAAAAAAAAAAAAAAAAAAABxuqd19rls44nS2aYrp6I4yClgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu/TW9jccurWba5MPw2j0dwOsAAAAAAAAAAAAAAAAAAAAAAAACmdVb2M+/wDs1trTDGn/ABT2g4oAAAAAAAAAAAAAAAAAAAAAAAIABIAAIBIAAAAAOv0zvo23MIpedKZo8s+GvcC7AAAAAAAAAAAAAAAAAAAAAAAA1+Ybum02mTPfsrHD0z3A88yZLZMlr2+a0zM+0HyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEzE6xwmOyQXnp/mUbzY1i1tc+L4ckd/okHUAAAAAAAAAAAAAAAAAAAAAABTuqeZ/f3MbbFbXFi+bSeE2/2A4YAAAAAAAAAAAAAAAAAAAAAAAAIBIAAAAAAAAAAANzlXMcmw3dc1eNJ4ZK+NQX7BnxZ8NM2KfNjvGtZB9gAAAAAAAAAAAAAAAAAAAA5XP+b12O28lJ/wARkjSkeEeIKPMzMzM8ZnjMgAAAAAAAAgEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7XT3O52eSNvmt/h7zwmfpme/wBQLnExMRMTrE8YmAAAAAAAAAAAAAAAAAAAAavMuYYdjtrZsk8eylO+0goe93mbebm+fLOtrTwjwjwgGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFg6f6h/l4rtN1OuHXSmT9Ovj6AWytq2rFqzFqz2THGASAAAAAAAAAAAAAAAADW5hzHbbHBOXNbj9NI+a0+gFG5nzLPv9xObJwrHClI7KwDUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1+TdQ59jMYssTl2093fX1AuO23W33WKMuC8XpPfH5gygAAAAAAAAAAAAAA5nNue7XYV8v9pnnsxxPZ6wU3e77c7zNOXPbzWnsjuiPCAa4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANjZcw3WzyefBea8fir3T64BcOT87nf/AAXw2x5NNfNETNJ9oOqAAAAAAAAAAACL3ilLXnsrGs6AqvNeqNxbzYdrS2GO/Jbhb2R3Ar172vab3mbWtxm08ZkEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaeAOpy/p7f7zS01+1i/Xbh7oBYtl0zy7b/Fev3r+N+z3A61KUpWK0iK1jsiOEAkAAAAAAAAAAAAGtuuXbLdRMZ8VbTMaebTj7wcHf9IaVm+zvrP93f8AKQV7c7Tcba80zY5paPGAYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdDlvJN7vrVmlfLhmeOW3Zp6PEFq5f0/sNnEW8v3csfXfj7oB0/UAAAAAAAAAAAAAAAAADFuNrt9xSaZscXrPjAK5zTpOYicmxnXjxxW/KQVzLiy4ck48tZpevbWe0HyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6x4smW8Y8dZte3CKwC0co6WpTy5t78V+2MXdHr8QWKtK0rFaRFaxwiI7ASAAAAAAAAAAAAAAAAAAAADT5hyrZ76k1zU+PuyR80e0FP5pyTdbC+to8+GflyR+YOcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADZ2HL9zvs32sFdf1WnsiPSC68q5NtuX4/h+PNMfHkmOM+oG+AAAAAAAAAAAAAAAAAAAAAAACL0pes1vEWrMaTEgqnOumbYtdxsom2Ptti749XoBXgAQCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb3KuU5+YZorWNMUfPk7oBd9lsdvssEYcFdIj5rd8z4yDYAAAAAAAAAAAAAAAAAAAAAAAAAABXufdO0yxbdbSvly9t8cdk+mAVS1Zraa2jS0cJiQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADf5RynLzDcRWNa4a8cmTwgF5222w7bDXDhr5cdeyPzkGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAHC6h5DXc0tutvGm4rxvWPrj+kFPms1mYmNJjhMAAAAAgEgAAAAAAAAAAAAAAAAAAAAAAA2+Wcuzb/c1w4+Fe29+6IBe9ns8G0wVw4Y0rWOM98z4yDOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACu9R8ijJW2821f3Kxrkxx3x4wCqAAAAAAAAAAAAAAAAAAAAAAAAAAAAybfBl3GamHFHmvedIgF85VyzDsNtXHSNbzxyX75kG6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMRMaTxgFQ6l5LG2v/N4K/s3n9ysdlZn+kHBAAAAAAAAAAAAAAAAAAAAAAAAAA9QLl03yf8AlcP8zmjTPkjhE/TUHbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8ZsVM2K2LJGtLxpaPRIKHzjlmTl+6nHOs4rccVvGAaIAAAAAAAAAAAAAAIBIAIBIAAAAAO101yn+a3H38tf2MU66THC1vAFz7I0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoc55ZTf7S1NIjLXjjtpxifD2goeTHfHe1LxNbVnS0T4wD5BAAJAAAAAAAAAAAAAAAAAAABk223ybjPTDjjW15iIB6DsNnj2e1x7enGKRxnxnvkGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq9V8r8l432P5bzpljwnxBXAQCQAAAAAAAAAAAAAAAQCQAAAWnpPlkRSd9kj4p1ri9XfILIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFutti3OC+DLGtLxpIPPt9tL7TdZMF+2k6RPjHdIMAAAAAAAAAAAAAAAAAAAAAM+x2l93u8e3p23nSZ8I75B6Hgw0w4aYscaUpEVrHqB9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArnV3LvPipvaR8VPhy+qeyQVUAAAAAAAAAAAAAAAAAAAAFn6P2MxGXeWiNJ/bxz3/1pBZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfG4w0zYL4bxrXJWazE+kHnO52+Tb58mHJwvjtNZ9gMYAAAAAAAAAAAAAAAAAAPrHS2S9aV+a0xWPXPAHomx2tdrtMW3idft1iNfGe8GcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFT6v2Xk3GPd17MkeS0emvZ/AFeAAAABAJAAAAAAAAAAAAB2Ol9n9/mUZLRE0wR5uPjPCAXUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjzvaRuuW5sekeaI81NfGvEFAAAAAAAAAAAAAAAAAAABc+lNp9nl33Zj4s8+b2RwgHaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmNeAPPucbWdrzHNi00r5vNX1W4g0wAAAAAAAAAAAAAAAAfWPHbJkrjr815iI9oPR9rhrh2+PFXspWI90AyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq3WO10yYdzEcLRNLezjAK2AAAAAAAAAAAAAAAADpdPbf7/NcMTHw0nzz7AXsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK6l2/3uVZJiJm2PS8aegFHAAAAAAAAAAAAAAAABY+jcGuXPmn6Yise3iC1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx7nHGXb5Mc9lqzH8Aeb3rNL2rPbWZifYCAAAAAAAAAAAAAAAAXPpPD9vlnnnty3mfdwB2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAefc5w/Z5nuKd3nmY9vEGmAAAAAAAAAAAAAAAD0Dk2L7XK9vX+pEzr6QboAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKX1Zi8nNPNH10ifcDjAAAAAAAAAAAAAAAmtfNaK+M6A9I29Ipt8dYjSK1iP4AyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq3WWPTLt8kR21msyCtgAAAAAAAAAAAAAAy7Snn3WGvjev4g9IiNIiI7IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABXusseu2wX74vMe+AVMAAAAAAAAAAAAAAG1yvy/wCY7fzdnnjtB6GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADh9X+X/Lqa9vnjQFOAAAAAAAB//Z"
+export const LoginBg = "../Layout/LoginBg.jpg";
+
+export const BaseURL = "https://64df594871c3335b25827869.mockapi.io/"
+
+
+
+export const convert_data_to_select = (array = []) => {
+ if (typeof array === 'undefined' || !Array.isArray(array)) {
+ throw new Error("Expected an array argument")
+ }
+ let new_array :any = []
+ array.map((e:any) => new_array.push({ label: e?.name, value: e?.id }))
+
+ return new_array
+ }
+
+ export const FakeSelectData :any = [
+ {
+ name : "mhmad",
+ id : 1
+ },
+ {
+ name : "karim",
+ id : 2
+ },
+ {
+ name : "suliman",
+ id : 3
+ },
+ {
+ name : "ibrahim",
+ id : 4
+ },
+]
+
+
+export const hasValue = (fieldValue: any, name: string): boolean => {
+ if (Array.isArray(fieldValue)) {
+ return fieldValue.length > 0;
+ } else if (typeof fieldValue === "object") {
+ return Object.keys(fieldValue).length > 0;
+ } else {
+
+ return !!fieldValue;
+ }
+};
\ No newline at end of file
diff --git a/src/Layout/app/ErrorPage.tsx b/src/Layout/app/ErrorPage.tsx
new file mode 100644
index 0000000..c8ce7f0
--- /dev/null
+++ b/src/Layout/app/ErrorPage.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { Button, Result } from 'antd';
+import { useTranslation } from 'react-i18next'; // Import useTranslation hook
+import { useLocation, useNavigate } from 'react-router-dom';
+
+import { useQueryClient } from 'react-query';
+const ErrorPage: React.FC = () => {
+ const { t } = useTranslation(); // Initialize useTranslation hook
+ const naviagate = useNavigate()
+ const location = useLocation();
+ const queryClient = useQueryClient(); // Initialize useQueryClient hook
+
+
+ const handleRefetch = () => {
+
+ const firstPath = location.pathname.split('/')[1]; // Get the first path segment from the URL
+ console.log(firstPath,"firstPath");
+
+ queryClient.invalidateQueries(firstPath === "/" ? 'home' : firstPath);
+ };
+
+ const handleGoToLogin = () => {
+ naviagate("/")
+ };
+
+ return (
+
+ {t('errorPage.refetch')} {/* Translate button text */}
+ ,
+ ,
+ ]}
+ >
+
+
+ );
+};
+
+export default ErrorPage;
diff --git a/src/Layout/app/Etaxi.tsx b/src/Layout/app/Etaxi.tsx
new file mode 100644
index 0000000..dd85aa4
--- /dev/null
+++ b/src/Layout/app/Etaxi.tsx
@@ -0,0 +1,41 @@
+import React from 'react'
+
+const Etaxi = () => {
+ return (
+
+
+ )
+}
+
+export default Etaxi
\ No newline at end of file
diff --git a/src/Layout/app/Export.tsx b/src/Layout/app/Export.tsx
new file mode 100644
index 0000000..c6dea28
--- /dev/null
+++ b/src/Layout/app/Export.tsx
@@ -0,0 +1,11 @@
+import DashHeader from '../../Layout/Dashboard/DashHeader';
+import LyTable from '../Dashboard/LyTable';
+import LayoutModal from '../Dashboard/LayoutModal'
+
+
+
+export {
+ DashHeader,
+ LyTable,
+ LayoutModal
+}
\ No newline at end of file
diff --git a/src/Layout/app/Header.tsx b/src/Layout/app/Header.tsx
new file mode 100644
index 0000000..e0901b9
--- /dev/null
+++ b/src/Layout/app/Header.tsx
@@ -0,0 +1,74 @@
+import React from 'react'
+import { UserImageURL } from './Const'
+import Translate from '../../Components/Utils/Translate'
+import { useTranslation } from 'react-i18next'
+import { Menu, MenuItem, MenuButton } from '@szhsin/react-menu';
+import '@szhsin/react-menu/dist/index.css';
+import '@szhsin/react-menu/dist/transitions/slide.css';
+import { useNavigate } from 'react-router-dom';
+import useAuthState from '../../lib/state mangment/AuthState';
+import { GiHamburgerMenu } from 'react-icons/gi';
+import WithDrawer from './WithDrawer';
+import Sidebar from './SideBar';
+
+type TUserData =
+ {
+ username: string | null,
+ role: string | null
+ }
+
+
+const Header = () => {
+
+
+ const [t] = useTranslation();
+ const navigate = useNavigate()
+
+ const { logout , user} = useAuthState()
+ const handelClick = () => {
+ logout()
+ navigate('/auth')
+ }
+
+
+
+ return (
+
+
+ {/*
*/}
+ {/*
*/}
+
+
+
+
+
+
+ )
+}
+
+export default Header
\ No newline at end of file
diff --git a/src/Layout/app/KarimLogo.tsx b/src/Layout/app/KarimLogo.tsx
new file mode 100644
index 0000000..6c147ee
--- /dev/null
+++ b/src/Layout/app/KarimLogo.tsx
@@ -0,0 +1,54 @@
+import React from 'react'
+
+const KarimLogo = () => {
+ return (
+<>
+
+>
+ )
+}
+
+export default KarimLogo
\ No newline at end of file
diff --git a/src/Layout/app/Layout.tsx b/src/Layout/app/Layout.tsx
new file mode 100644
index 0000000..ca21133
--- /dev/null
+++ b/src/Layout/app/Layout.tsx
@@ -0,0 +1,39 @@
+import React, { useEffect } from 'react'
+import SideBar from './SideBar'
+import Header from './Header'
+import { useNavigate } from 'react-router-dom'
+import useAuthState from '../../lib/state mangment/AuthState'
+
+const Layout = ({ children }: { children: React.ReactNode }) => {
+
+
+ const navigate = useNavigate()
+ const { isAuthenticated } = useAuthState()
+ useEffect(() => {
+ if (!isAuthenticated) {
+
+ navigate('/auth')
+ }
+ }, [navigate])
+ return (
+ <>
+
+ >
+ )
+}
+
+export default Layout
\ No newline at end of file
diff --git a/src/Layout/app/LoadingPage.tsx b/src/Layout/app/LoadingPage.tsx
new file mode 100644
index 0000000..45d436f
--- /dev/null
+++ b/src/Layout/app/LoadingPage.tsx
@@ -0,0 +1,13 @@
+import React from 'react'
+import LoadingSpinner from '../../Components/Ui/LoadingSpinner'
+import { Spin } from 'antd'
+
+function LoadingPage() {
+ return (
+
+
+
+ )
+}
+
+export default LoadingPage
\ No newline at end of file
diff --git a/src/Layout/app/NotFoundPage.tsx b/src/Layout/app/NotFoundPage.tsx
new file mode 100644
index 0000000..316349a
--- /dev/null
+++ b/src/Layout/app/NotFoundPage.tsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import { useNavigate } from 'react-router-dom'
+
+function NotFoundPage() {
+ const navigate = useNavigate()
+ return (
+
+
+
+
404
|
This page could not be found
+
+
+
+ )
+}
+
+export default NotFoundPage
\ No newline at end of file
diff --git a/src/Layout/app/SideBar.tsx b/src/Layout/app/SideBar.tsx
new file mode 100644
index 0000000..8016a30
--- /dev/null
+++ b/src/Layout/app/SideBar.tsx
@@ -0,0 +1,116 @@
+import React, { useEffect, useState } from 'react';
+import { FaAngleDown, FaAngleRight } from 'react-icons/fa';
+import { GiHamburgerMenu } from 'react-icons/gi';
+import { Link, useLocation } from 'react-router-dom';
+import { RoutesLinks } from '../../Routes';
+import { useTranslation } from 'react-i18next';
+import KarimLogo from './KarimLogo';
+import { useWindowSize } from '../../Hooks/useWindowSize';
+import Etaxi from './Etaxi';
+import { usePageState } from '../../lib/state mangment/LayoutPagestate';
+
+interface SidebarProps {}
+
+const Sidebar: React.FC = () => {
+ const { pathname } = useLocation();
+ // const {isOpenAddModel ,isOpenEditModel} = usePageState(state => state)
+ // useEffect(() => {
+ // if(isOpenAddModel || isOpenEditModel){
+ // setIsOpenSide(true);
+ // document.getElementById('DashboardLayout_Body')?.classList.add('DashboardLayout_Body_Open');
+ // }
+
+
+
+ // }, [isOpenAddModel ,isOpenEditModel])
+
+
+
+ const [isOpenSide, setIsOpenSide] = useState(false);
+ const [openDropdown, setOpenDropdown] = useState(null);
+ const [t] = useTranslation();
+ const windowSize = useWindowSize()
+
+ const handleHamburgerMenu = () => {
+ setIsOpenSide(true);
+ document.getElementById('DashboardLayout_Body')?.classList.add('DashboardLayout_Body_Open');
+ };
+
+ const handleImg = () => {
+ setIsOpenSide(false);
+ document.getElementById('DashboardLayout_Body')?.classList.remove('DashboardLayout_Body_Open');
+ setOpenDropdown(null);
+ };
+
+ const handleDropdown = (index: number) => {
+ setOpenDropdown((prev) => (prev === index ? null : index));
+ };
+
+ return (
+
+
+
+

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

+
+
+
+
+
+
+
+ )
+}
+
+export default Auth
\ No newline at end of file
diff --git a/src/Pages/Auth/formUtil.ts b/src/Pages/Auth/formUtil.ts
new file mode 100644
index 0000000..e660741
--- /dev/null
+++ b/src/Pages/Auth/formUtil.ts
@@ -0,0 +1,23 @@
+
+import * as Yup from "yup";
+
+
+export const getInitialValues = (): any => {
+
+
+ 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/ContactUs/Page.tsx b/src/Pages/ContactUs/Page.tsx
new file mode 100644
index 0000000..6252e13
--- /dev/null
+++ b/src/Pages/ContactUs/Page.tsx
@@ -0,0 +1,54 @@
+
+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 { useGetContactUs } from '../../api/ContactUs'
+
+function Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGetContactUs()
+ // const navigate = useNavigate()
+ const ExpandedComponent = ({ data }:any) => {
+ console.log(data,"data");
+
+ return (
+
+
message : {data?.message}
+
+ );
+ };
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+ {/*
navigate('/contact_us/add')}> */}
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Page
+
diff --git a/src/Pages/ContactUs/View/AddForm.tsx b/src/Pages/ContactUs/View/AddForm.tsx
new file mode 100644
index 0000000..0627b63
--- /dev/null
+++ b/src/Pages/ContactUs/View/AddForm.tsx
@@ -0,0 +1,30 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/ContactUs/View/AddPage.tsx b/src/Pages/ContactUs/View/AddPage.tsx
new file mode 100644
index 0000000..aa6460c
--- /dev/null
+++ b/src/Pages/ContactUs/View/AddPage.tsx
@@ -0,0 +1,56 @@
+import { getInitialValuesForAdd as getInitialValues, getValidationSchema, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { useTranslation } from 'react-i18next';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import { useAddContactUs } from '../../../api/ContactUs';
+import Form from './AddForm';
+
+const AddContactUsPage = () => {
+
+
+ const { mutate, isLoading:IsloadingButton, isSuccess } = useAddContactUs()
+ const handleSubmit = (values: any) => {
+ const transformedValues = { ...values }; // Create a new object
+
+ mutate(transformedValues);
+ };
+
+
+ const { t } = useTranslation();
+
+ useNavigateOnSuccess(isSuccess, '/contact_us')
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default AddContactUsPage
\ No newline at end of file
diff --git a/src/Pages/ContactUs/View/EditForm.tsx b/src/Pages/ContactUs/View/EditForm.tsx
new file mode 100644
index 0000000..0627b63
--- /dev/null
+++ b/src/Pages/ContactUs/View/EditForm.tsx
@@ -0,0 +1,30 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/ContactUs/View/EditPage.tsx b/src/Pages/ContactUs/View/EditPage.tsx
new file mode 100644
index 0000000..71a7fbc
--- /dev/null
+++ b/src/Pages/ContactUs/View/EditPage.tsx
@@ -0,0 +1,71 @@
+import React, { useEffect } from 'react'
+import { getInitialValues, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { Spin } from 'antd';
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetOneContactUs, useUpdateContactUs } from '../../../api/ContactUs';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const { data,isLoading:IsloadingButton,isRefetching } = useGetOneContactUs()
+ const { mutate, isSuccess } = useUpdateContactUs()
+ const handleSubmit = (values: any) => {
+ mutate(values);
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/contact_us')
+
+
+ useEffect(() => {
+
+ setObjectToEdit(data?.data);
+
+ }, [data?.data, setObjectToEdit]);
+
+
+ const getValidationSchema = () => {
+ return null
+ };
+ if ( IsloadingButton || !objectToEdit || isRefetching) {
+ return
+ }
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+ {objectToEdit && data ?
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+ :
}
+
+
+
+ )
+
+}
+
+export default EditPage
\ No newline at end of file
diff --git a/src/Pages/ContactUs/formUtil.ts b/src/Pages/ContactUs/formUtil.ts
new file mode 100644
index 0000000..9184d24
--- /dev/null
+++ b/src/Pages/ContactUs/formUtil.ts
@@ -0,0 +1,60 @@
+
+import * as Yup from "yup";
+import { buildFormData } from "../../api/helper/buildFormData";
+
+
+
+export const getInitialValues = (objectToEdit: any | null = null): any => {
+ //@ts-ignore
+ return {
+ id: objectToEdit?.id ?? null,
+ name: objectToEdit?.name ,
+ email: objectToEdit?.email ,
+ message: objectToEdit?.message ,
+
+
+ };
+};
+
+export const getInitialValuesForAdd = (objectToEdit: any | null = null): any => {
+ return {
+ name: null ,
+ email: null ,
+ message: null ,
+
+
+
+ };
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // Validate input
+ return Yup.object().shape({
+ name: Yup.string().required('Required'),
+ email: Yup.string().required('Required'),
+ message: Yup.string().required('Required'),
+
+
+ });
+};
+
+
+
+export const getDataToSend = (values: any): FormData => {
+ const data = { ...values };
+
+
+ const formData = new FormData();
+ buildFormData(formData, data);
+ return formData;
+};
+
+export const ChangeDataToPrint = (data: any) => {
+
+ let new_array = data
+ for (let i = 0; i < data.length; i++) {
+ new_array[i]['status'] = !data[i]['deleted_at'] ? 'available' : 'unavailable'
+ delete new_array[i]['deleted_at']
+ }
+ return new_array
+}
\ No newline at end of file
diff --git a/src/Pages/ContactUs/useTableColumns.tsx b/src/Pages/ContactUs/useTableColumns.tsx
new file mode 100644
index 0000000..5e94d42
--- /dev/null
+++ b/src/Pages/ContactUs/useTableColumns.tsx
@@ -0,0 +1,58 @@
+
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../Components/Ui/tables/Actions";
+
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+ return useMemo(
+ () => [
+
+ {
+ name: t("id"),
+ sortable: true,
+ center: true,
+ selector: (row: any) => row.id,
+ },
+ {
+ name: t("name"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.name
+ },
+ {
+ name: t("email"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.email
+ },
+
+ {
+ name: t("message"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => {row?.message}
+ },
+ {
+ name: "#",
+ sortable: false,
+ center: true,
+ cell: (row:any) => (
+
+
+ ),
+ },
+
+ ],
+ [t]
+ );
+};
+
+export default useTableColumns;
+
diff --git a/src/Pages/Developer/Page.tsx b/src/Pages/Developer/Page.tsx
new file mode 100644
index 0000000..f77a091
--- /dev/null
+++ b/src/Pages/Developer/Page.tsx
@@ -0,0 +1,43 @@
+
+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 { useGetDeveloper } from '../../api/Developer'
+
+function Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGetDeveloper()
+ const navigate = useNavigate()
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+
navigate('/developer/add')}>
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Page
+
diff --git a/src/Pages/Developer/View/AddForm.tsx b/src/Pages/Developer/View/AddForm.tsx
new file mode 100644
index 0000000..2c32b64
--- /dev/null
+++ b/src/Pages/Developer/View/AddForm.tsx
@@ -0,0 +1,30 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Developer/View/AddPage.tsx b/src/Pages/Developer/View/AddPage.tsx
new file mode 100644
index 0000000..004c01f
--- /dev/null
+++ b/src/Pages/Developer/View/AddPage.tsx
@@ -0,0 +1,56 @@
+import { getInitialValuesForAdd as getInitialValues, getValidationSchema, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { useTranslation } from 'react-i18next';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import { useAddDeveloper } from '../../../api/Developer';
+import Form from './AddForm';
+
+const AddDeveloperPage = () => {
+
+
+ const { mutate, isLoading:IsloadingButton, isSuccess } = useAddDeveloper()
+ const handleSubmit = (values: any) => {
+ const transformedValues = { ...values }; // Create a new object
+
+ mutate(transformedValues);
+ };
+
+
+ const { t } = useTranslation();
+
+ useNavigateOnSuccess(isSuccess, '/developer')
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default AddDeveloperPage
\ No newline at end of file
diff --git a/src/Pages/Developer/View/EditForm.tsx b/src/Pages/Developer/View/EditForm.tsx
new file mode 100644
index 0000000..2c32b64
--- /dev/null
+++ b/src/Pages/Developer/View/EditForm.tsx
@@ -0,0 +1,30 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Developer/View/EditPage.tsx b/src/Pages/Developer/View/EditPage.tsx
new file mode 100644
index 0000000..664a4dd
--- /dev/null
+++ b/src/Pages/Developer/View/EditPage.tsx
@@ -0,0 +1,74 @@
+import React, { useEffect } from 'react'
+import { getInitialValues, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { Spin } from 'antd';
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetOneDeveloper, useUpdateDeveloper } from '../../../api/Developer';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const { data,isLoading:IsloadingButton,isRefetching } = useGetOneDeveloper()
+ const { mutate, isSuccess } = useUpdateDeveloper()
+ const handleSubmit = (values: any) => {
+ if(typeof values?.image === "string"){
+ delete values["image"]
+ }
+ mutate(values);
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/developer')
+
+
+ useEffect(() => {
+
+ setObjectToEdit(data?.data);
+
+ }, [data?.data, setObjectToEdit]);
+
+
+ const getValidationSchema = () => {
+ return null
+ };
+ if ( IsloadingButton || !objectToEdit || isRefetching) {
+ return
+ }
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+ {objectToEdit && data ?
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+ :
}
+
+
+
+ )
+
+}
+
+export default EditPage
\ No newline at end of file
diff --git a/src/Pages/Developer/formUtil.ts b/src/Pages/Developer/formUtil.ts
new file mode 100644
index 0000000..2c5f89a
--- /dev/null
+++ b/src/Pages/Developer/formUtil.ts
@@ -0,0 +1,61 @@
+
+import * as Yup from "yup";
+import { buildFormData } from "../../api/helper/buildFormData";
+import * as dayjs from 'dayjs'
+
+
+
+export const getInitialValues = (objectToEdit: any | null = null): any => {
+ //@ts-ignore
+ return {
+ id: objectToEdit?.id ?? null,
+ name: objectToEdit?.name ,
+ image: objectToEdit?.image ,
+ description: objectToEdit?.description ,
+
+
+ };
+};
+
+export const getInitialValuesForAdd = (objectToEdit: any | null = null): any => {
+ return {
+ name: null ,
+ image: null ,
+ description: null ,
+
+
+
+ };
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // Validate input
+ return Yup.object().shape({
+ name: Yup.string().required('Required'),
+ image: Yup.string().required('Required'),
+ description: Yup.string().required('Required'),
+
+
+ });
+};
+
+
+
+export const getDataToSend = (values: any): FormData => {
+ const data = { ...values };
+
+
+ const formData = new FormData();
+ buildFormData(formData, data);
+ return formData;
+};
+
+export const ChangeDataToPrint = (data: any) => {
+
+ let new_array = data
+ for (let i = 0; i < data.length; i++) {
+ new_array[i]['status'] = !data[i]['deleted_at'] ? 'available' : 'unavailable'
+ delete new_array[i]['deleted_at']
+ }
+ return new_array
+}
\ No newline at end of file
diff --git a/src/Pages/Developer/useTableColumns.tsx b/src/Pages/Developer/useTableColumns.tsx
new file mode 100644
index 0000000..5c74511
--- /dev/null
+++ b/src/Pages/Developer/useTableColumns.tsx
@@ -0,0 +1,68 @@
+
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../Components/Ui/tables/Actions";
+import { useNavigate } from "react-router-dom";
+import { useDeleteDeveloper } from "../../api/Developer";
+import ColumnsImage from "../../Components/Columns/ColumnsImage";
+
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+ const deleteMutation = useDeleteDeveloper()
+ const navigate = useNavigate()
+ return useMemo(
+ () => [
+
+ {
+ name: t("id"),
+ sortable: true,
+ center: true,
+ selector: (row: any) => row.id,
+ },
+ {
+ name: t("image"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => {
+ let src = row?.image;
+ return
+ }
+
+ },
+ {
+ name: t("name"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.name
+ },
+
+ {
+ name: t("description"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.description
+ },
+ {
+ name: "#",
+ sortable: false,
+ center: true,
+ cell: (row:any) => (
+ navigate(`/developer/${row.id}`) }
+ showView={false}
+ onDelete={() => deleteMutation.mutate({ id: row.id })}
+ >
+
+ ),
+ },
+
+ ],
+ [deleteMutation, navigate, t]
+ );
+};
+
+export default useTableColumns;
+
diff --git a/src/Pages/Key/Page.tsx b/src/Pages/Key/Page.tsx
new file mode 100644
index 0000000..f50aaab
--- /dev/null
+++ b/src/Pages/Key/Page.tsx
@@ -0,0 +1,54 @@
+
+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 { useGetKey } from '../../api/Key'
+import SelectField from '../../Layout/Dashboard/SelectField'
+
+function Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGetKey()
+ const navigate = useNavigate()
+ const typeselect = [
+ {label : "home" , value : "home"},
+ {label : "setting" , value : "setting"},
+ {label : "contact_us" , value : "contact_us"},
+ {label : "about_us" , value : "about_us"}
+
+
+ ]
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+
+
navigate('/key/add')}>
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Page
+
diff --git a/src/Pages/Key/View/AddForm.tsx b/src/Pages/Key/View/AddForm.tsx
new file mode 100644
index 0000000..ca6f193
--- /dev/null
+++ b/src/Pages/Key/View/AddForm.tsx
@@ -0,0 +1,38 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ const typeselect = [
+ {label : "home" , value : "home"},
+ {label : "setting" , value : "setting"},
+ {label : "contact_us" , value : "contact_us"},
+ {label : "about_us" , value : "about_us"}
+
+
+ ]
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Key/View/AddPage.tsx b/src/Pages/Key/View/AddPage.tsx
new file mode 100644
index 0000000..34cd51b
--- /dev/null
+++ b/src/Pages/Key/View/AddPage.tsx
@@ -0,0 +1,56 @@
+import { getInitialValuesForAdd as getInitialValues, getValidationSchema, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { useTranslation } from 'react-i18next';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import { useAddKey } from '../../../api/Key';
+import Form from './AddForm';
+
+const AddKeyPage = () => {
+
+
+ const { mutate, isLoading:IsloadingButton, isSuccess } = useAddKey()
+ const handleSubmit = (values: any) => {
+ const transformedValues = { ...values }; // Create a new object
+
+ mutate(transformedValues);
+ };
+
+
+ const { t } = useTranslation();
+
+ useNavigateOnSuccess(isSuccess, '/key')
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default AddKeyPage
\ No newline at end of file
diff --git a/src/Pages/Key/View/EditForm.tsx b/src/Pages/Key/View/EditForm.tsx
new file mode 100644
index 0000000..ca6f193
--- /dev/null
+++ b/src/Pages/Key/View/EditForm.tsx
@@ -0,0 +1,38 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ const typeselect = [
+ {label : "home" , value : "home"},
+ {label : "setting" , value : "setting"},
+ {label : "contact_us" , value : "contact_us"},
+ {label : "about_us" , value : "about_us"}
+
+
+ ]
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Key/View/EditPage.tsx b/src/Pages/Key/View/EditPage.tsx
new file mode 100644
index 0000000..8aded32
--- /dev/null
+++ b/src/Pages/Key/View/EditPage.tsx
@@ -0,0 +1,72 @@
+import React, { useEffect } from 'react'
+import { getInitialValues, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { Spin } from 'antd';
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetOneKey, useUpdateKey } from '../../../api/Key';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const { data,isLoading:IsloadingButton,isRefetching } = useGetOneKey()
+ const { mutate, isSuccess } = useUpdateKey()
+ const handleSubmit = (values: any) => {
+
+ mutate(values);
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/key')
+
+
+ useEffect(() => {
+
+ setObjectToEdit(data?.data);
+
+ }, [data?.data, setObjectToEdit]);
+
+
+ const getValidationSchema = () => {
+ return null
+ };
+ if ( IsloadingButton || !objectToEdit || isRefetching) {
+ return
+ }
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+ {objectToEdit && data ?
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+ :
}
+
+
+
+ )
+
+}
+
+export default EditPage
\ No newline at end of file
diff --git a/src/Pages/Key/formUtil.ts b/src/Pages/Key/formUtil.ts
new file mode 100644
index 0000000..3aff4df
--- /dev/null
+++ b/src/Pages/Key/formUtil.ts
@@ -0,0 +1,61 @@
+
+import * as Yup from "yup";
+import { buildFormData } from "../../api/helper/buildFormData";
+import * as dayjs from 'dayjs'
+
+
+
+export const getInitialValues = (objectToEdit: any | null = null): any => {
+ //@ts-ignore
+ return {
+ id: objectToEdit?.id ?? null,
+ key: objectToEdit?.key ,
+ type: objectToEdit?.type ,
+ value: objectToEdit?.value ,
+
+
+ };
+};
+
+export const getInitialValuesForAdd = (objectToEdit: any | null = null): any => {
+ return {
+ key: null ,
+ type: null ,
+ value: null ,
+
+
+
+ };
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // Validate input
+ return Yup.object().shape({
+ key: Yup.string().required('Required'),
+ type: Yup.string().required('Required'),
+ value: Yup.string().required('Required'),
+
+
+ });
+};
+
+
+
+export const getDataToSend = (values: any): FormData => {
+ const data = { ...values };
+
+
+ const formData = new FormData();
+ buildFormData(formData, data);
+ return formData;
+};
+
+export const ChangeDataToPrint = (data: any) => {
+
+ let new_array = data
+ for (let i = 0; i < data.length; i++) {
+ new_array[i]['status'] = !data[i]['deleted_at'] ? 'available' : 'unavailable'
+ delete new_array[i]['deleted_at']
+ }
+ return new_array
+}
\ No newline at end of file
diff --git a/src/Pages/Key/useTableColumns.tsx b/src/Pages/Key/useTableColumns.tsx
new file mode 100644
index 0000000..65755c8
--- /dev/null
+++ b/src/Pages/Key/useTableColumns.tsx
@@ -0,0 +1,64 @@
+
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../Components/Ui/tables/Actions";
+import { useNavigate } from "react-router-dom";
+import { useDeleteKey } from "../../api/Key";
+
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+ const deleteMutation = useDeleteKey()
+ const navigate = useNavigate()
+ return useMemo(
+ () => [
+
+ {
+ name: t("id"),
+ sortable: true,
+ center: true,
+ selector: (row: any) => row.id,
+ },
+ {
+ name: t("key"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.key
+ },
+
+ {
+ name: t("value"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.value
+ },
+
+ {
+ name: t("type"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.type
+ },
+ {
+ name: "#",
+ sortable: false,
+ center: true,
+ cell: (row:any) => (
+ navigate(`/key/${row.id}`) }
+ showView={false}
+ onDelete={() => deleteMutation.mutate({ id: row.id })}
+ >
+
+ ),
+ },
+
+ ],
+ [deleteMutation, navigate, t]
+ );
+};
+
+export default useTableColumns;
+
diff --git a/src/Pages/Project/Page.tsx b/src/Pages/Project/Page.tsx
new file mode 100644
index 0000000..b792507
--- /dev/null
+++ b/src/Pages/Project/Page.tsx
@@ -0,0 +1,43 @@
+
+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 { useGetProject } from '../../api/Project'
+
+function Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGetProject()
+ const navigate = useNavigate()
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+
navigate('/project/add')}>
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Page
+
diff --git a/src/Pages/Project/ProjectImage/DataTable/Page.tsx b/src/Pages/Project/ProjectImage/DataTable/Page.tsx
new file mode 100644
index 0000000..d73a79e
--- /dev/null
+++ b/src/Pages/Project/ProjectImage/DataTable/Page.tsx
@@ -0,0 +1,44 @@
+
+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, useParams } from 'react-router-dom'
+import AddButton from '../../../../Layout/Dashboard/AddButton/AddButton'
+import { useGetProjectImage } from '../../../../api/Project'
+
+function Page() {
+
+ const column =useTableColumns()
+ const {id} = useParams()
+ const {data ,status } = useGetProjectImage({project_id:id})
+ const navigate = useNavigate()
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+
navigate('project_image/add')}>
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Page
+
diff --git a/src/Pages/Project/ProjectImage/DataTable/formUtil.ts b/src/Pages/Project/ProjectImage/DataTable/formUtil.ts
new file mode 100644
index 0000000..a64b4e0
--- /dev/null
+++ b/src/Pages/Project/ProjectImage/DataTable/formUtil.ts
@@ -0,0 +1,56 @@
+
+import * as Yup from "yup";
+import { buildFormData } from "../../../../api/helper/buildFormData";
+
+
+
+export const getInitialValues = (objectToEdit: any | null = null): any => {
+ //@ts-ignore
+ return {
+ id: objectToEdit?.id ?? null,
+ image: objectToEdit?.image ,
+ type: objectToEdit?.type ,
+ is_active: objectToEdit?.is_active ,
+
+
+ };
+};
+
+export const getInitialValuesForAdd = (objectToEdit: any | null = null): any => {
+ return {
+ image: null ,
+ type: null ,
+ is_active: 0 ,
+
+ };
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // Validate input
+ return Yup.object().shape({
+ image: Yup.string().required('Required'),
+ type: Yup.string().required('Required'),
+
+ });
+};
+
+
+
+export const getDataToSend = (values: any): FormData => {
+ const data = { ...values };
+
+
+ const formData = new FormData();
+ buildFormData(formData, data);
+ return formData;
+};
+
+export const ChangeDataToPrint = (data: any) => {
+
+ let new_array = data
+ for (let i = 0; i < data.length; i++) {
+ new_array[i]['status'] = !data[i]['deleted_at'] ? 'available' : 'unavailable'
+ delete new_array[i]['deleted_at']
+ }
+ return new_array
+}
\ No newline at end of file
diff --git a/src/Pages/Project/ProjectImage/DataTable/useTableColumns.tsx b/src/Pages/Project/ProjectImage/DataTable/useTableColumns.tsx
new file mode 100644
index 0000000..110c4fb
--- /dev/null
+++ b/src/Pages/Project/ProjectImage/DataTable/useTableColumns.tsx
@@ -0,0 +1,67 @@
+
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../../../Components/Ui/tables/Actions";
+import { useNavigate } from "react-router-dom";
+import { useDeleteProjectImage } from "../../../../api/Project";
+import ColumnsImage from "../../../../Components/Columns/ColumnsImage";
+
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+ const deleteMutation = useDeleteProjectImage()
+ const navigate = useNavigate()
+ return useMemo(
+ () => [
+
+ {
+ name: t("id"),
+ sortable: true,
+ center: true,
+ selector: (row: any) => row.id,
+ },
+ {
+ name: t("image"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => {
+ let src = row?.image;
+ return
+ }
+
+ },
+ {
+ name: t("type"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.type
+ },
+
+ {
+ name: t("is_active"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.is_active
+ },
+ {
+ name: "#",
+ sortable: false,
+ center: true,
+ cell: (row:any) => (
+ deleteMutation.mutate({ id: row.id })}
+ >
+
+ ),
+ },
+
+ ],
+ [deleteMutation, navigate, t]
+ );
+};
+
+export default useTableColumns;
+
diff --git a/src/Pages/Project/ProjectImage/View/AddForm.tsx b/src/Pages/Project/ProjectImage/View/AddForm.tsx
new file mode 100644
index 0000000..9d4dafc
--- /dev/null
+++ b/src/Pages/Project/ProjectImage/View/AddForm.tsx
@@ -0,0 +1,54 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../../Components/ValidationField/ValidationField';
+import { useFormikContext } from 'formik';
+import { Switch } from 'antd';
+import { useTranslation } from 'react-i18next';
+
+function Form() {
+ const { values,setFieldValue } = useFormikContext();
+ const [t] = useTranslation()
+ const onChange = (checked: boolean) => {
+ console.log(`switch to ${checked}`);
+
+ setFieldValue("is_active", checked ? 1 : 0)
+
+ };
+ const typeselect = [
+ {label : "website" , value : "website"},
+ {label : "mobile" , value : "mobile"},
+
+
+ ]
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Project/ProjectImage/View/AddPage.tsx b/src/Pages/Project/ProjectImage/View/AddPage.tsx
new file mode 100644
index 0000000..5ada121
--- /dev/null
+++ b/src/Pages/Project/ProjectImage/View/AddPage.tsx
@@ -0,0 +1,64 @@
+import { getInitialValuesForAdd as getInitialValues, getValidationSchema, getDataToSend } from '../DataTable/formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../../Layout/Dashboard/ViewPage';
+import { useTranslation } from 'react-i18next';
+
+import Form from './AddForm';
+import { useNavigate, useParams } from 'react-router-dom';
+import { useAddProjectImage } from '../../../../api/Project';
+import { useEffect } from 'react';
+
+const AddProjectPage = () => {
+
+
+ const navigate = useNavigate()
+ const { mutate, isLoading:IsloadingButton,isSuccess } = useAddProjectImage()
+ const {id} = useParams()
+ const handleSubmit = (values: any) => {
+ const transformedValues = { ...values , project_id:id }; // Create a new object
+
+ mutate(transformedValues);
+ };
+
+useEffect(() => {
+ if(isSuccess){
+ navigate(-1)
+
+ }
+}, [isSuccess,navigate])
+
+ const { t } = useTranslation();
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default AddProjectPage
\ No newline at end of file
diff --git a/src/Pages/Project/View/AddForm.tsx b/src/Pages/Project/View/AddForm.tsx
new file mode 100644
index 0000000..6bff29d
--- /dev/null
+++ b/src/Pages/Project/View/AddForm.tsx
@@ -0,0 +1,30 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Project/View/AddPage.tsx b/src/Pages/Project/View/AddPage.tsx
new file mode 100644
index 0000000..904f5ba
--- /dev/null
+++ b/src/Pages/Project/View/AddPage.tsx
@@ -0,0 +1,56 @@
+import { getInitialValuesForAdd as getInitialValues, getValidationSchema, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { useTranslation } from 'react-i18next';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import { useAddProject } from '../../../api/Project';
+import Form from './AddForm';
+
+const AddProjectPage = () => {
+
+
+ const { mutate, isLoading:IsloadingButton, isSuccess } = useAddProject()
+ const handleSubmit = (values: any) => {
+ const transformedValues = { ...values }; // Create a new object
+
+ mutate(transformedValues);
+ };
+
+
+ const { t } = useTranslation();
+
+ useNavigateOnSuccess(isSuccess, '/project')
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default AddProjectPage
\ No newline at end of file
diff --git a/src/Pages/Project/View/EditForm.tsx b/src/Pages/Project/View/EditForm.tsx
new file mode 100644
index 0000000..6bff29d
--- /dev/null
+++ b/src/Pages/Project/View/EditForm.tsx
@@ -0,0 +1,30 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Project/View/EditPage.tsx b/src/Pages/Project/View/EditPage.tsx
new file mode 100644
index 0000000..4109c00
--- /dev/null
+++ b/src/Pages/Project/View/EditPage.tsx
@@ -0,0 +1,83 @@
+import React, { useEffect } from 'react'
+import { getInitialValues, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { Spin } from 'antd';
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetOneProject, useUpdateProject } from '../../../api/Project';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+import Page from '../ProjectImage/DataTable/Page';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const { data,isLoading:IsloadingButton,isRefetching } = useGetOneProject()
+ const { mutate, isSuccess } = useUpdateProject()
+ const handleSubmit = (values: any) => {
+ if(typeof values?.logo === "string"){
+ delete values["logo"]
+ }
+ mutate(values);
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/project')
+
+
+ useEffect(() => {
+
+ setObjectToEdit(data?.data);
+
+ }, [data?.data, setObjectToEdit]);
+
+
+ const getValidationSchema = () => {
+ return null
+ };
+ if ( IsloadingButton || !objectToEdit || isRefetching) {
+ return
+ }
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+ {objectToEdit && data ?
+
+
+
+
{t("BasicInfo")}
+
{t("ProductImage")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :
}
+
+
+
+ )
+
+}
+
+export default EditPage
\ No newline at end of file
diff --git a/src/Pages/Project/formUtil.ts b/src/Pages/Project/formUtil.ts
new file mode 100644
index 0000000..64ebf0a
--- /dev/null
+++ b/src/Pages/Project/formUtil.ts
@@ -0,0 +1,60 @@
+
+import * as Yup from "yup";
+import { buildFormData } from "../../api/helper/buildFormData";
+
+
+
+export const getInitialValues = (objectToEdit: any | null = null): any => {
+ //@ts-ignore
+ return {
+ id: objectToEdit?.id ?? null,
+ title: objectToEdit?.title ,
+ logo: objectToEdit?.logo ,
+ description: objectToEdit?.description ,
+
+
+ };
+};
+
+export const getInitialValuesForAdd = (objectToEdit: any | null = null): any => {
+ return {
+ title: null ,
+ logo: null ,
+ description: null ,
+
+
+
+ };
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // Validate input
+ return Yup.object().shape({
+ title: Yup.string().required('Required'),
+ logo: Yup.string().required('Required'),
+ description: Yup.string().required('Required'),
+
+
+ });
+};
+
+
+
+export const getDataToSend = (values: any): FormData => {
+ const data = { ...values };
+
+
+ const formData = new FormData();
+ buildFormData(formData, data);
+ return formData;
+};
+
+export const ChangeDataToPrint = (data: any) => {
+
+ let new_array = data
+ for (let i = 0; i < data.length; i++) {
+ new_array[i]['status'] = !data[i]['deleted_at'] ? 'available' : 'unavailable'
+ delete new_array[i]['deleted_at']
+ }
+ return new_array
+}
\ No newline at end of file
diff --git a/src/Pages/Project/useTableColumns.tsx b/src/Pages/Project/useTableColumns.tsx
new file mode 100644
index 0000000..0cb3345
--- /dev/null
+++ b/src/Pages/Project/useTableColumns.tsx
@@ -0,0 +1,68 @@
+
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../Components/Ui/tables/Actions";
+import { useNavigate } from "react-router-dom";
+import { useDeleteProject } from "../../api/Project";
+import ColumnsImage from "../../Components/Columns/ColumnsImage";
+
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+ const deleteMutation = useDeleteProject()
+ const navigate = useNavigate()
+ return useMemo(
+ () => [
+
+ {
+ name: t("id"),
+ sortable: true,
+ center: true,
+ selector: (row: any) => row.id,
+ },
+ {
+ name: t("logo"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => {
+ let src = row?.logo;
+ return
+ }
+
+ },
+ {
+ name: t("title"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.title
+ },
+
+ {
+ name: t("description"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.description
+ },
+ {
+ name: "#",
+ sortable: false,
+ center: true,
+ cell: (row:any) => (
+ navigate(`/project/${row.id}`) }
+ showView={false}
+ onDelete={() => deleteMutation.mutate({ id: row.id })}
+ >
+
+ ),
+ },
+
+ ],
+ [deleteMutation, navigate, t]
+ );
+};
+
+export default useTableColumns;
+
diff --git a/src/Pages/RequestQuotation/Page.tsx b/src/Pages/RequestQuotation/Page.tsx
new file mode 100644
index 0000000..11b32a4
--- /dev/null
+++ b/src/Pages/RequestQuotation/Page.tsx
@@ -0,0 +1,54 @@
+
+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 { useGetRequestQuotation } from '../../api/RequestQuotation'
+
+function Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGetRequestQuotation()
+ // const navigate = useNavigate()
+ const ExpandedComponent = ({ data }:any) => {
+ console.log(data,"data");
+
+ return (
+
+
message : {data?.message}
+
+ );
+ };
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+ {/*
navigate('/quotation/add')}> */}
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Page
+
diff --git a/src/Pages/RequestQuotation/View/AddForm.tsx b/src/Pages/RequestQuotation/View/AddForm.tsx
new file mode 100644
index 0000000..0627b63
--- /dev/null
+++ b/src/Pages/RequestQuotation/View/AddForm.tsx
@@ -0,0 +1,30 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/RequestQuotation/View/AddPage.tsx b/src/Pages/RequestQuotation/View/AddPage.tsx
new file mode 100644
index 0000000..a1c964e
--- /dev/null
+++ b/src/Pages/RequestQuotation/View/AddPage.tsx
@@ -0,0 +1,56 @@
+import { getInitialValuesForAdd as getInitialValues, getValidationSchema, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { useTranslation } from 'react-i18next';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import { useAddRequestQuotation } from '../../../api/RequestQuotation';
+import Form from './AddForm';
+
+const AddRequestQuotationPage = () => {
+
+
+ const { mutate, isLoading:IsloadingButton, isSuccess } = useAddRequestQuotation()
+ const handleSubmit = (values: any) => {
+ const transformedValues = { ...values }; // Create a new object
+
+ mutate(transformedValues);
+ };
+
+
+ const { t } = useTranslation();
+
+ useNavigateOnSuccess(isSuccess, '/request_quotation')
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default AddRequestQuotationPage
\ No newline at end of file
diff --git a/src/Pages/RequestQuotation/View/EditForm.tsx b/src/Pages/RequestQuotation/View/EditForm.tsx
new file mode 100644
index 0000000..0627b63
--- /dev/null
+++ b/src/Pages/RequestQuotation/View/EditForm.tsx
@@ -0,0 +1,30 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/RequestQuotation/View/EditPage.tsx b/src/Pages/RequestQuotation/View/EditPage.tsx
new file mode 100644
index 0000000..4167274
--- /dev/null
+++ b/src/Pages/RequestQuotation/View/EditPage.tsx
@@ -0,0 +1,71 @@
+import React, { useEffect } from 'react'
+import { getInitialValues, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { Spin } from 'antd';
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetOneContactUs, useUpdateContactUs } from '../../../api/ContactUs';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const { data,isLoading:IsloadingButton,isRefetching } = useGetOneContactUs()
+ const { mutate, isSuccess } = useUpdateContactUs()
+ const handleSubmit = (values: any) => {
+ mutate(values);
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/request_quotation')
+
+
+ useEffect(() => {
+
+ setObjectToEdit(data?.data);
+
+ }, [data?.data, setObjectToEdit]);
+
+
+ const getValidationSchema = () => {
+ return null
+ };
+ if ( IsloadingButton || !objectToEdit || isRefetching) {
+ return
+ }
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+ {objectToEdit && data ?
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+ :
}
+
+
+
+ )
+
+}
+
+export default EditPage
\ No newline at end of file
diff --git a/src/Pages/RequestQuotation/formUtil.ts b/src/Pages/RequestQuotation/formUtil.ts
new file mode 100644
index 0000000..9184d24
--- /dev/null
+++ b/src/Pages/RequestQuotation/formUtil.ts
@@ -0,0 +1,60 @@
+
+import * as Yup from "yup";
+import { buildFormData } from "../../api/helper/buildFormData";
+
+
+
+export const getInitialValues = (objectToEdit: any | null = null): any => {
+ //@ts-ignore
+ return {
+ id: objectToEdit?.id ?? null,
+ name: objectToEdit?.name ,
+ email: objectToEdit?.email ,
+ message: objectToEdit?.message ,
+
+
+ };
+};
+
+export const getInitialValuesForAdd = (objectToEdit: any | null = null): any => {
+ return {
+ name: null ,
+ email: null ,
+ message: null ,
+
+
+
+ };
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // Validate input
+ return Yup.object().shape({
+ name: Yup.string().required('Required'),
+ email: Yup.string().required('Required'),
+ message: Yup.string().required('Required'),
+
+
+ });
+};
+
+
+
+export const getDataToSend = (values: any): FormData => {
+ const data = { ...values };
+
+
+ const formData = new FormData();
+ buildFormData(formData, data);
+ return formData;
+};
+
+export const ChangeDataToPrint = (data: any) => {
+
+ let new_array = data
+ for (let i = 0; i < data.length; i++) {
+ new_array[i]['status'] = !data[i]['deleted_at'] ? 'available' : 'unavailable'
+ delete new_array[i]['deleted_at']
+ }
+ return new_array
+}
\ No newline at end of file
diff --git a/src/Pages/RequestQuotation/useTableColumns.tsx b/src/Pages/RequestQuotation/useTableColumns.tsx
new file mode 100644
index 0000000..2d14815
--- /dev/null
+++ b/src/Pages/RequestQuotation/useTableColumns.tsx
@@ -0,0 +1,80 @@
+
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../Components/Ui/tables/Actions";
+import { Button } from "antd";
+
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+ return useMemo(
+ () => [
+
+ {
+ name: t("id"),
+ sortable: true,
+ center: true,
+ selector: (row: any) => row.id,
+ },
+ {
+ name: t("name"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.name
+ },
+ {
+ name: t("email"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.email
+ },
+ {
+ name: t("phone"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.phone
+ },
+
+ {
+ name: t("message"),
+ width:"200",
+ sortable: false,
+ center: "true",
+ cell: (row:any) => {row?.message}
+ },
+ {
+ name: t("attachment"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => {
+ let src = row?.attachment;
+ const handleClick = () => {
+ if (row?.attachment) {
+ window.open(row.attachment, '_blank');
+ }
+ };
+ return
+ }
+ },
+ {
+ name: "#",
+ sortable: false,
+ center: true,
+ cell: (row:any) => (
+
+
+ ),
+ },
+
+ ],
+ [t]
+ );
+};
+
+export default useTableColumns;
+
diff --git a/src/Pages/Service/Page.tsx b/src/Pages/Service/Page.tsx
new file mode 100644
index 0000000..5e08b8b
--- /dev/null
+++ b/src/Pages/Service/Page.tsx
@@ -0,0 +1,43 @@
+
+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 { useGetService } from '../../api/Service'
+
+function Page() {
+
+ const column =useTableColumns()
+ const {data ,status } = useGetService()
+ const navigate = useNavigate()
+
+ return (
+ // Pass Status to Layout
+
+
+
+
+
+
navigate('/service/add')}>
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Page
+
diff --git a/src/Pages/Service/View/AddForm.tsx b/src/Pages/Service/View/AddForm.tsx
new file mode 100644
index 0000000..0627b63
--- /dev/null
+++ b/src/Pages/Service/View/AddForm.tsx
@@ -0,0 +1,30 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Service/View/AddPage.tsx b/src/Pages/Service/View/AddPage.tsx
new file mode 100644
index 0000000..5fcbb1c
--- /dev/null
+++ b/src/Pages/Service/View/AddPage.tsx
@@ -0,0 +1,56 @@
+import { getInitialValuesForAdd as getInitialValues, getValidationSchema, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { useTranslation } from 'react-i18next';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import { useAddService } from '../../../api/Service';
+import Form from './AddForm';
+
+const AddServicePage = () => {
+
+
+ const { mutate, isLoading:IsloadingButton, isSuccess } = useAddService()
+ const handleSubmit = (values: any) => {
+ const transformedValues = { ...values }; // Create a new object
+
+ mutate(transformedValues);
+ };
+
+
+ const { t } = useTranslation();
+
+ useNavigateOnSuccess(isSuccess, '/service')
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default AddServicePage
\ No newline at end of file
diff --git a/src/Pages/Service/View/EditForm.tsx b/src/Pages/Service/View/EditForm.tsx
new file mode 100644
index 0000000..0627b63
--- /dev/null
+++ b/src/Pages/Service/View/EditForm.tsx
@@ -0,0 +1,30 @@
+
+import { Col, Row } from 'reactstrap';
+import ValidationField from '../../../Components/ValidationField/ValidationField';
+
+function Form() {
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Form
+
+
+
+
diff --git a/src/Pages/Service/View/EditPage.tsx b/src/Pages/Service/View/EditPage.tsx
new file mode 100644
index 0000000..58ec5ae
--- /dev/null
+++ b/src/Pages/Service/View/EditPage.tsx
@@ -0,0 +1,74 @@
+import React, { useEffect } from 'react'
+import { getInitialValues, getDataToSend } from '../formUtil'
+import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
+import 'react-tabs/style/react-tabs.css';
+import { MdLanguage } from 'react-icons/md'
+import ViewPage from '../../../Layout/Dashboard/ViewPage';
+import { Spin } from 'antd';
+import { usePageState } from '../../../lib/state mangment/LayoutPagestate';
+import LoadingPage from '../../../Layout/app/LoadingPage';
+import { useTranslation } from 'react-i18next';
+import { useGetOneService, useUpdateService } from '../../../api/Service';
+import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
+import Form from './EditForm';
+
+const EditPage = () => {
+ const { setObjectToEdit, objectToEdit } = usePageState()
+ const { t } = useTranslation();
+ const { data,isLoading:IsloadingButton,isRefetching } = useGetOneService()
+ const { mutate, isSuccess } = useUpdateService()
+ const handleSubmit = (values: any) => {
+ if(typeof values?.image === "string"){
+ delete values["image"]
+ }
+ mutate(values);
+}
+
+
+ useNavigateOnSuccess(isSuccess, '/service')
+
+
+ useEffect(() => {
+
+ setObjectToEdit(data?.data);
+
+ }, [data?.data, setObjectToEdit]);
+
+
+ const getValidationSchema = () => {
+ return null
+ };
+ if ( IsloadingButton || !objectToEdit || isRefetching) {
+ return
+ }
+
+
+
+ const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
+
+
+ return (
+
+ {objectToEdit && data ?
+
+
+
+
{t("BasicInfo")}
+
+
+
+
+
+
+
+
+
+ :
}
+
+
+
+ )
+
+}
+
+export default EditPage
\ No newline at end of file
diff --git a/src/Pages/Service/formUtil.ts b/src/Pages/Service/formUtil.ts
new file mode 100644
index 0000000..43ef72f
--- /dev/null
+++ b/src/Pages/Service/formUtil.ts
@@ -0,0 +1,61 @@
+
+import * as Yup from "yup";
+import { buildFormData } from "../../api/helper/buildFormData";
+import * as dayjs from 'dayjs'
+
+
+
+export const getInitialValues = (objectToEdit: any | null = null): any => {
+ //@ts-ignore
+ return {
+ id: objectToEdit?.id ?? null,
+ title: objectToEdit?.title ,
+ image: objectToEdit?.image ,
+ description: objectToEdit?.description ,
+
+
+ };
+};
+
+export const getInitialValuesForAdd = (objectToEdit: any | null = null): any => {
+ return {
+ title: null ,
+ image: null ,
+ description: null ,
+
+
+
+ };
+};
+
+export const getValidationSchema = (editMode: boolean = false): Yup.Schema => {
+ // Validate input
+ return Yup.object().shape({
+ title: Yup.string().required('Required'),
+ image: Yup.string().required('Required'),
+ description: Yup.string().required('Required'),
+
+
+ });
+};
+
+
+
+export const getDataToSend = (values: any): FormData => {
+ const data = { ...values };
+
+
+ const formData = new FormData();
+ buildFormData(formData, data);
+ return formData;
+};
+
+export const ChangeDataToPrint = (data: any) => {
+
+ let new_array = data
+ for (let i = 0; i < data.length; i++) {
+ new_array[i]['status'] = !data[i]['deleted_at'] ? 'available' : 'unavailable'
+ delete new_array[i]['deleted_at']
+ }
+ return new_array
+}
\ No newline at end of file
diff --git a/src/Pages/Service/useTableColumns.tsx b/src/Pages/Service/useTableColumns.tsx
new file mode 100644
index 0000000..333b570
--- /dev/null
+++ b/src/Pages/Service/useTableColumns.tsx
@@ -0,0 +1,68 @@
+
+import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import Actions from "../../Components/Ui/tables/Actions";
+import { useNavigate } from "react-router-dom";
+import { useDeleteService } from "../../api/Service";
+import ColumnsImage from "../../Components/Columns/ColumnsImage";
+
+
+const useTableColumns :any = () => {
+ const [t] = useTranslation();
+ const deleteMutation = useDeleteService()
+ const navigate = useNavigate()
+ return useMemo(
+ () => [
+
+ {
+ name: t("id"),
+ sortable: true,
+ center: true,
+ selector: (row: any) => row.id,
+ },
+ {
+ name: t("image"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => {
+ let src = row?.image;
+ return
+ }
+
+ },
+ {
+ name: t("title"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.title
+ },
+
+ {
+ name: t("description"),
+ sortable: false,
+ center: "true",
+ cell: (row:any) => row?.description
+ },
+ {
+ name: "#",
+ sortable: false,
+ center: true,
+ cell: (row:any) => (
+ navigate(`/service/${row.id}`) }
+ showView={false}
+ onDelete={() => deleteMutation.mutate({ id: row.id })}
+ >
+
+ ),
+ },
+
+ ],
+ [deleteMutation, navigate, t]
+ );
+};
+
+export default useTableColumns;
+
diff --git a/src/ProviderContainer.tsx b/src/ProviderContainer.tsx
new file mode 100644
index 0000000..c30c964
--- /dev/null
+++ b/src/ProviderContainer.tsx
@@ -0,0 +1,24 @@
+import React, { ReactNode } from 'react'
+import QueryProvider from './lib/ReactQueryProvider'
+import { BrowserRouter } from 'react-router-dom'
+import ToastProvider from './lib/ToastProvider'
+import { createBrowserHistory } from 'history'
+
+type ProviderContainerProps = {
+ children:ReactNode
+
+}
+export let history = createBrowserHistory()
+function ProviderContainer({children}:ProviderContainerProps) {
+ return (
+
+
+
+ {children}
+
+
+
+ )
+}
+
+export default ProviderContainer
\ No newline at end of file
diff --git a/src/Routes.tsx b/src/Routes.tsx
new file mode 100644
index 0000000..e101e93
--- /dev/null
+++ b/src/Routes.tsx
@@ -0,0 +1,156 @@
+import { ReactNode } from "react";
+
+
+
+
+// Pages Import
+
+
+
+//// service page
+import ServicePage from "./Pages/Service/Page";
+import AddServicePage from "./Pages/Service/View/AddPage";
+import EditService from "./Pages/Service/View/EditPage";
+
+
+
+
+//// Developer page
+import DeveloperPage from "./Pages/Developer/Page";
+import AddDeveloperPage from "./Pages/Developer/View/AddPage";
+import EditDeveloper from "./Pages/Developer/View/EditPage";
+
+
+//// Project page
+import ProjectPage from "./Pages/Project/Page";
+import AddProjectPage from "./Pages/Project/View/AddPage";
+import EditProject from "./Pages/Project/View/EditPage";
+import AddProjectImagePage from "./Pages/Project/ProjectImage/View/AddPage";
+
+
+
+//// Key page
+import KeyPage from "./Pages/Key/Page";
+import AddKeyPage from "./Pages/Key/View/AddPage";
+import EditKey from "./Pages/Key/View/EditPage";
+
+
+
+//// ContactUs page
+import ContactUsPage from "./Pages/ContactUs/Page";
+
+//// RequestQuotation page
+import RequestQuotationPage from "./Pages/RequestQuotation/Page";
+
+
+/// icons
+import { FaServicestack } from "react-icons/fa";
+import { ContactsOutlined, HomeFilled, ProjectFilled } from "@ant-design/icons";
+import { MdDeveloperBoard } from "react-icons/md";
+import { BsKey } from "react-icons/bs";
+
+
+interface RoutesLinksType {
+ name?: string,
+ href?: string,
+ element?: ReactNode,
+ icon?: any,
+ Viewelement?: ReactNode,
+ Viewhref?: string
+ children?: any
+ hidden?: boolean
+}
+export const RoutesLinks: RoutesLinksType[] = [
+
+
+
+ {
+ name: "Home",
+ element: Home Page
,
+ icon: ,
+ href: "/",
+ },
+ {
+ name: "service",
+ element: ,
+ icon: ,
+ href: "/service",
+ },
+ {
+ href: "/service/:id",
+ element: ,
+ hidden:true
+ },
+ {
+ href: "/service/add",
+ element: ,
+ hidden:true
+ },
+
+ {
+ name: "Developer",
+ element: ,
+ icon: ,
+ href: "/developer",
+ },
+ {
+ href: "/developer/:id",
+ element: ,
+ hidden:true
+ },
+ {
+ href: "/developer/add",
+ element: ,
+ hidden:true
+ },
+ {
+ name: "Project",
+ element: ,
+ icon: ,
+ href: "/project",
+ },
+ {
+ href: "/project/:id",
+ element: ,
+ hidden:true
+ },
+ {
+ href: "/project/add",
+ element: ,
+ hidden:true
+ },
+ {
+ href: "/project/:id/project_image/add",
+ element: ,
+ hidden:true
+ },
+ {
+ name: "Key",
+ element: ,
+ icon: ,
+ href: "/key",
+ },
+ {
+ href: "/key/:id",
+ element: ,
+ hidden:true
+ },
+ {
+ href: "/key/add",
+ element: ,
+ hidden:true
+ },
+
+ {
+ name: "contact us",
+ element: ,
+ icon: ,
+ href: "/contact_us",
+ },
+ {
+ name: "quotation",
+ element: ,
+ icon: ,
+ href: "/quotation",
+ },
+]
\ 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..07f8d11
--- /dev/null
+++ b/src/Styles/AppStyle/Import.scss
@@ -0,0 +1,22 @@
+
+@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/SingleDriverInfo.scss';
+@import '../component/DriverInfoSocket.scss';
+@import '../component/radio.scss';
+
+@import '../Layout/FillterSection.scss';
+
+
+
+
diff --git a/src/Styles/AppStyle/Mixing.scss b/src/Styles/AppStyle/Mixing.scss
new file mode 100644
index 0000000..fb26134
--- /dev/null
+++ b/src/Styles/AppStyle/Mixing.scss
@@ -0,0 +1,27 @@
+
+@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);
+}
+.single-line-div {
+ max-width: 150px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
\ 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..3ba8319
--- /dev/null
+++ b/src/Styles/AppStyle/Varibils.scss
@@ -0,0 +1,25 @@
+:root {
+ --primary:#55338A ;
+ --secondary : #ffca00;
+ --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:#55338A ;
+ --secondary : #ffca00;
+ --text: #ffffff;
+ --bg: #1f1f1f;
+ --bg2: #2c2c2c;
+ --shadow: rgba(255, 255, 255, 0.15);
+ --gray: #a0aec0;
+ --linear : linear-gradient(118deg, #fcb04f, #f78c3f)
+
+
+}
+
+
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/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..b2ca97d
--- /dev/null
+++ b/src/Styles/Layout/Header.scss
@@ -0,0 +1,112 @@
+.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;
+
+ @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;
+ }
+}
+}
\ 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..38a13b0
--- /dev/null
+++ b/src/Styles/Layout/Layout.scss
@@ -0,0 +1,525 @@
+
+///// 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;
+ }
+
+
+
+ }
+
+ /* 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);
+
+
+ }
+}
+
+/* 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: 300px;
+}
+.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;
+ }
+
+}
+.custoumSelectField{
+ width: 150px !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..ce385ac
--- /dev/null
+++ b/src/Styles/Layout/SideBar.scss
@@ -0,0 +1,353 @@
+
+
+.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;
+ }
+ .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(--primary);
+ 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/SingleDriverInfo.scss b/src/Styles/component/SingleDriverInfo.scss
new file mode 100644
index 0000000..931d462
--- /dev/null
+++ b/src/Styles/component/SingleDriverInfo.scss
@@ -0,0 +1,13 @@
+
+.SignleDriverContainer{
+ display: flex;justify-content: start;align-items: center;
+ .SingleDriverInfo{
+ font-size: 1.4vw;
+ padding-left: .5vw;
+ }
+ .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/ContactUs.ts b/src/api/ContactUs.ts
new file mode 100644
index 0000000..9bc781f
--- /dev/null
+++ b/src/api/ContactUs.ts
@@ -0,0 +1,24 @@
+
+import useGetQueryPagination from "./helper/ueGetPagination";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetOneQuery from "./helper/useGetOneQuery";
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `contact_us`,
+ GET_ALL: `contact_us`,
+ DELETE: `contact_us`,
+ UPDATE: `contact_us`,
+
+};
+const KEY = "contact_us"
+
+
+export const useGetContactUs = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params);
+export const useGetOneContactUs = () => useGetOneQuery(KEY, API.GET_ALL);
+
+export const useAddContactUs = () => useAddMutation(KEY, API.ADD);
+export const useUpdateContactUs = () => useUpdateMutation(KEY, API.UPDATE,true);
+
+export const useDeleteContactUs = () =>useDeleteMutation(KEY, API.DELETE);
diff --git a/src/api/Developer.ts b/src/api/Developer.ts
new file mode 100644
index 0000000..09168ba
--- /dev/null
+++ b/src/api/Developer.ts
@@ -0,0 +1,24 @@
+
+import useGetQueryPagination from "./helper/ueGetPagination";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetOneQuery from "./helper/useGetOneQuery";
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `developer`,
+ GET_ALL: `developer`,
+ DELETE: `developer`,
+ UPDATE: `developer`,
+
+};
+const KEY = "developer"
+
+
+export const useGetDeveloper = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params);
+export const useGetOneDeveloper = () => useGetOneQuery(KEY, API.GET_ALL);
+
+export const useAddDeveloper = () => useAddMutation(KEY, API.ADD);
+export const useUpdateDeveloper = () => useUpdateMutation(KEY, API.UPDATE,true);
+
+export const useDeleteDeveloper = () =>useDeleteMutation(KEY, API.DELETE);
diff --git a/src/api/Key.ts b/src/api/Key.ts
new file mode 100644
index 0000000..2bdbf1e
--- /dev/null
+++ b/src/api/Key.ts
@@ -0,0 +1,24 @@
+
+import useGetQueryPagination from "./helper/ueGetPagination";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetOneQuery from "./helper/useGetOneQuery";
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `key`,
+ GET_ALL: `key`,
+ DELETE: `key`,
+ UPDATE: `key`,
+
+};
+const KEY = "key"
+
+
+export const useGetKey = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params);
+export const useGetOneKey = () => useGetOneQuery(KEY, API.GET_ALL);
+
+export const useAddKey = () => useAddMutation(KEY, API.ADD);
+export const useUpdateKey = () => useUpdateMutation(KEY, API.UPDATE,true);
+
+export const useDeleteKey = () =>useDeleteMutation(KEY, API.DELETE);
diff --git a/src/api/Project.ts b/src/api/Project.ts
new file mode 100644
index 0000000..23b99a5
--- /dev/null
+++ b/src/api/Project.ts
@@ -0,0 +1,36 @@
+
+import useGetQueryPagination from "./helper/ueGetPagination";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetOneQuery from "./helper/useGetOneQuery";
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `project`,
+ GET_ALL: `project`,
+ DELETE: `project`,
+ UPDATE: `project`,
+
+ GET_ALL_IMAGE: `project_image`,
+
+ ADD_IMAGE: `project_image`,
+ DELETE_IMAGE: `project_image`,
+ UPDATE_IMAGE: `project_image`,
+
+};
+const KEY = "project"
+
+
+export const useGetProject = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params);
+export const useGetOneProject = () => useGetOneQuery(KEY, API.GET_ALL);
+
+export const useAddProject = () => useAddMutation(KEY, API.ADD);
+export const useUpdateProject = () => useUpdateMutation(KEY, API.UPDATE,true);
+
+export const useDeleteProject = () =>useDeleteMutation(KEY, API.DELETE);
+
+export const useGetProjectImage = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL_IMAGE,params);
+
+export const useAddProjectImage = () => useAddMutation(KEY, API.ADD_IMAGE);
+
+export const useDeleteProjectImage = () =>useDeleteMutation(KEY, API.DELETE_IMAGE);
diff --git a/src/api/RequestQuotation.ts b/src/api/RequestQuotation.ts
new file mode 100644
index 0000000..1b32355
--- /dev/null
+++ b/src/api/RequestQuotation.ts
@@ -0,0 +1,24 @@
+
+import useGetQueryPagination from "./helper/ueGetPagination";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetOneQuery from "./helper/useGetOneQuery";
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `quotation`,
+ GET_ALL: `quotation`,
+ DELETE: `quotation`,
+ UPDATE: `quotation`,
+
+};
+const KEY = "quotation"
+
+
+export const useGetRequestQuotation = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params);
+export const useGetOneRequestQuotation = () => useGetOneQuery(KEY, API.GET_ALL);
+
+export const useAddRequestQuotation = () => useAddMutation(KEY, API.ADD);
+export const useUpdateRequestQuotation = () => useUpdateMutation(KEY, API.UPDATE,true);
+
+export const useDeleteRequestQuotation = () =>useDeleteMutation(KEY, API.DELETE);
diff --git a/src/api/Service.ts b/src/api/Service.ts
new file mode 100644
index 0000000..3ee7d67
--- /dev/null
+++ b/src/api/Service.ts
@@ -0,0 +1,24 @@
+
+import useGetQueryPagination from "./helper/ueGetPagination";
+import useAddMutation from "./helper/useAddMutation"
+import useDeleteMutation from "./helper/useDeleteMutation"
+import useGetOneQuery from "./helper/useGetOneQuery";
+import useUpdateMutation from "./helper/useUpdateMutation";
+
+const API = {
+ ADD: `service`,
+ GET_ALL: `service`,
+ DELETE: `service`,
+ UPDATE: `service`,
+
+};
+const KEY = "service"
+
+
+export const useGetService = (params?:any) => useGetQueryPagination(KEY, API.GET_ALL,params);
+export const useGetOneService = () => useGetOneQuery(KEY, API.GET_ALL);
+
+export const useAddService = () => useAddMutation(KEY, API.ADD);
+export const useUpdateService = () => useUpdateMutation(KEY, API.UPDATE,true);
+
+export const useDeleteService = () =>useDeleteMutation(KEY, API.DELETE);
diff --git a/src/api/auth.ts b/src/api/auth.ts
new file mode 100644
index 0000000..734e65a
--- /dev/null
+++ b/src/api/auth.ts
@@ -0,0 +1,11 @@
+import useAddMutation from "./helper/useAddMutation";
+
+
+
+
+const KEY = "auth"
+const API = {
+ LOGIN: `login`,
+ LOGOUT: `logout`,
+ };
+export const useLoginAdmin = ()=>useAddMutation(KEY , API.LOGIN,"login_succsefuly")
\ No newline at end of file
diff --git a/src/api/config.ts b/src/api/config.ts
new file mode 100644
index 0000000..57634c0
--- /dev/null
+++ b/src/api/config.ts
@@ -0,0 +1,11 @@
+
+// export const BaseURL = `https://etaxiapi.rayantaxi.com/`;
+// export const BaseURL = `https://etaxi.Point.net/`;
+export const BaseURL = `http://127.0.0.1:8000/api/`;
+
+const PROJECT_NAME = "Point"
+
+export const TOKEN_KEY = PROJECT_NAME + "_TOKEN"
+
+export const USER_KEY = PROJECT_NAME + "_USER"
+
diff --git a/src/api/helper/AxiosBuilder.ts b/src/api/helper/AxiosBuilder.ts
new file mode 100644
index 0000000..3f19067
--- /dev/null
+++ b/src/api/helper/AxiosBuilder.ts
@@ -0,0 +1,49 @@
+import axios, { AxiosInstance, AxiosRequestConfig ,ResponseType } from 'axios';
+
+
+class AxiosBuilder {
+ private baseURL: string = '';
+ private headers: Record = {};
+ private timeout: number = 60000; // Request failed with 60 second
+ private withCreds: boolean = false;
+ private responseType: ResponseType = 'json';
+ // Custom Another Props with Your Position
+
+
+ withBaseURL(baseURL: string): AxiosBuilder {
+ this.baseURL = baseURL;
+ return this;
+ }
+
+ withHeaders(headers: Record): AxiosBuilder {
+ this.headers = headers;
+ return this;
+ }
+
+ withTimeout(timeout: number): AxiosBuilder {
+ this.timeout = timeout;
+ return this;
+ }
+
+
+ withResponseType(responseType: ResponseType): AxiosBuilder {
+ this.responseType = responseType;
+ return this;
+ }
+
+
+ build(): AxiosInstance {
+ const config: AxiosRequestConfig = {
+ baseURL: this.baseURL,
+ headers: this.headers,
+ timeout: this.timeout,
+ responseType:this.responseType
+ };
+
+ return axios.create(config);
+ }
+ }
+
+
+export default AxiosBuilder
+
diff --git a/src/api/helper/Get.ts b/src/api/helper/Get.ts
new file mode 100644
index 0000000..9a97c04
--- /dev/null
+++ b/src/api/helper/Get.ts
@@ -0,0 +1,18 @@
+import { useQuery } from 'react-query';
+import useAxios from './useAxios';
+
+function useGetQuery(key: string, url: string , params:any) {
+ const axios = useAxios();
+
+ return useQuery(key, async () => {
+ const response = await axios.get( params ? url+params: url , params);
+ return response.data.data;
+ }, {
+ onError: (error) => {
+ console.error('An error occurred:', error);
+ },
+ refetchOnWindowFocus: false,
+ });
+}
+
+export default useGetQuery;
diff --git a/src/api/helper/buildFormData.ts b/src/api/helper/buildFormData.ts
new file mode 100644
index 0000000..eb1f736
--- /dev/null
+++ b/src/api/helper/buildFormData.ts
@@ -0,0 +1,27 @@
+
+
+export const buildFormData = (
+ formData: FormData,
+ data: any,
+ parentKey?: string
+ ): void => {
+ if (
+ data &&
+ typeof data === "object" &&
+ !(data instanceof Date) &&
+ !(data instanceof File)
+ ) {
+ Object.keys(data).forEach((key) => {
+ buildFormData(
+ formData,
+ data[key],
+ parentKey ? `${parentKey}[${key}]` : key
+ );
+ });
+ } else {
+ const value = data == null ? "" : data;
+
+ formData.append(parentKey as string, value);
+ }
+ };
+
\ No newline at end of file
diff --git a/src/api/helper/ueGetPagination.ts b/src/api/helper/ueGetPagination.ts
new file mode 100644
index 0000000..4a3e657
--- /dev/null
+++ b/src/api/helper/ueGetPagination.ts
@@ -0,0 +1,43 @@
+import { useQuery } from 'react-query';
+import useAxios from './useAxios';
+import { useLocation, useNavigate } from 'react-router-dom';
+import useAuthState from '../../lib/state mangment/AuthState';
+
+export default function useGetQueryPagination(KEY: string | string[], Api: string, params: any = {}, options: any = {}, dontSearchBy?: string) {
+ const axios = useAxios();
+ const location = useLocation();
+ let pagination = location?.search || '';
+
+ const { logout } = useAuthState();
+ const navigate = useNavigate();
+
+ if (dontSearchBy && pagination.includes(dontSearchBy)) {
+ const searchParams = new URLSearchParams(pagination);
+ searchParams.delete(dontSearchBy);
+ pagination = searchParams.toString();
+ }
+ if (pagination && !pagination.startsWith('?')) {
+ pagination = '?' + pagination;
+ }
+
+ // Check if pagination exists and append it to the API endpoint
+ const paginationParams = pagination ;
+ const apiUrl = Api + paginationParams;
+
+ return useQuery(
+ [Array.isArray(KEY) ? KEY.join(',') : KEY, pagination], async () => {
+ const response = await axios.get(apiUrl, { params });
+ return response.data.data;
+ },
+ {
+ onError: (error: any) => {
+ if (error?.response?.status === 401 || error?.response?.status === 403) {
+ logout();
+ navigate("/auth");
+ }
+ },
+ refetchOnWindowFocus: false,
+ ...options
+ }
+ );
+}
diff --git a/src/api/helper/useAddMutation.ts b/src/api/helper/useAddMutation.ts
new file mode 100644
index 0000000..8ec9c17
--- /dev/null
+++ b/src/api/helper/useAddMutation.ts
@@ -0,0 +1,39 @@
+import { useMutation, useQueryClient, UseMutationResult } from 'react-query';
+import { toast } from 'react-toastify';
+import useAxios from './useAxios';
+import { useTranslation } from 'react-i18next';
+
+type AxiosResponse = {
+ message: string;
+ data:any ,
+ success:true
+};
+
+function useAddMutation(key: string, url: string,message?:string): UseMutationResult {
+ const axios = useAxios();
+ const [t] = useTranslation();
+ const queryClient = useQueryClient();
+
+ return useMutation(
+ async (dataToSend) => {
+ const { data } = await axios.post(url, dataToSend,{
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ } );
+ return data.data;
+ },
+ {
+ onSuccess: (data) => {
+ queryClient.invalidateQueries([key]);
+ toast.success(data.message || t(message ?? "added_successful"));
+ },
+ onError: (error:any) => {
+ const message = error?.response?.data?.message || t("failed_to_add_data");
+ toast.error(message);
+ }
+ }
+ );
+}
+
+export default useAddMutation;
diff --git a/src/api/helper/useAddMutationJson.ts b/src/api/helper/useAddMutationJson.ts
new file mode 100644
index 0000000..8e9864b
--- /dev/null
+++ b/src/api/helper/useAddMutationJson.ts
@@ -0,0 +1,35 @@
+import { useMutation, useQueryClient, UseMutationResult } from 'react-query';
+import { toast } from 'react-toastify';
+import useAxios from './useAxios';
+import { useTranslation } from 'react-i18next';
+
+type AxiosResponse = {
+ message: string;
+ data:any ,
+ success:true
+};
+
+function useAddMutationJson(key: string, url: string): UseMutationResult {
+ const axios = useAxios();
+ const [t] = useTranslation();
+ const queryClient = useQueryClient();
+
+ return useMutation(
+ async (dataToSend) => {
+ const { data } = await axios.post(url, dataToSend);
+ return data;
+ },
+ {
+ onSuccess: (data) => {
+ queryClient.invalidateQueries([key]);
+ toast.success(data.message || t("added_successful"));
+ },
+ onError: (error:any) => {
+ const message = error?.response?.data?.message || t("failed_to_add_data");
+ toast.error(message);
+ }
+ }
+ );
+}
+
+export default useAddMutationJson;
diff --git a/src/api/helper/useAxios.ts b/src/api/helper/useAxios.ts
new file mode 100644
index 0000000..0b06694
--- /dev/null
+++ b/src/api/helper/useAxios.ts
@@ -0,0 +1,25 @@
+import { BaseURL } from '../config'
+import useAuthState from '../../lib/state mangment/AuthState'
+import AxiosBuilder from './AxiosBuilder'
+
+function useAxios() {
+ const {isAuthenticated , token}= useAuthState()
+
+ const buildAxios = new AxiosBuilder()
+ .withBaseURL(BaseURL)
+ .withResponseType('json')
+ .withTimeout(120000)
+ .withHeaders({"Content-Type" :"application/json"})
+
+
+ if(isAuthenticated){
+
+ buildAxios.withHeaders({ Authorization: 'Bearer '+ token })
+ }
+
+ return (
+ buildAxios.build()
+ )
+}
+
+export default useAxios
\ No newline at end of file
diff --git a/src/api/helper/useDeleteMutation.ts b/src/api/helper/useDeleteMutation.ts
new file mode 100644
index 0000000..87e84ca
--- /dev/null
+++ b/src/api/helper/useDeleteMutation.ts
@@ -0,0 +1,35 @@
+import { useMutation, useQueryClient, UseMutationResult } from 'react-query';
+import { toast } from 'react-toastify';
+import useAxios from './useAxios';
+import { useTranslation } from 'react-i18next';
+
+type AxiosResponse = {
+ message: string;
+ // Add other properties as needed
+};
+
+function useDeleteMutation(key:any , url: string): UseMutationResult {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const {t} = useTranslation();
+
+ return useMutation(
+ async ({dataToSend,id}:any) => {
+ const { data } = await axios.delete(url+"/"+id );
+ return {...data, id,dataToSend};
+ },
+ {
+ onSuccess: (data) => {
+ queryClient.invalidateQueries(key);
+ toast.success(t('deleted_successfully'));
+ },
+ onError: (error:any) => {
+ const message = error?.response?.data?.message || t("failed_to_add_data");
+ toast.error(message);
+ }
+ },
+
+ );
+}
+
+export default useDeleteMutation;
diff --git a/src/api/helper/useGetOneQuery.ts b/src/api/helper/useGetOneQuery.ts
new file mode 100644
index 0000000..ace6655
--- /dev/null
+++ b/src/api/helper/useGetOneQuery.ts
@@ -0,0 +1,39 @@
+import { useQuery } from 'react-query';
+import useAxios from './useAxios';
+import useAuthState from '../../lib/state mangment/AuthState';
+import { useNavigate, useParams } from 'react-router-dom';
+
+function useGetOneQuery(key: string, url: string , params:any={},options:any={}) {
+ const axios = useAxios();
+ const {logout} = useAuthState()
+ const language = localStorage.getItem("language") ?? "en"
+ const navigate = useNavigate()
+ const {id} = useParams()
+
+ return useQuery(
+ [id, key],
+ async () => {
+ const response = await axios.get(url+"/"+ id+`?lang=${language}`);
+ return response.data?.data;
+ },
+
+
+ {
+ onError: (error:any) => {
+ if(error.response.status == 401 || error.response.status == 403){
+ logout()
+ navigate("/auth")
+
+ }
+
+ },
+ cacheTime: 0, // Set cacheTime to 0 to disable caching
+ refetchOnWindowFocus: false,
+
+ ...options
+
+ }
+ );
+}
+
+export default useGetOneQuery;
diff --git a/src/api/helper/useGetQuery.ts b/src/api/helper/useGetQuery.ts
new file mode 100644
index 0000000..02e9cd9
--- /dev/null
+++ b/src/api/helper/useGetQuery.ts
@@ -0,0 +1,39 @@
+import { useQuery } from 'react-query';
+import useAxios from './useAxios';
+import useAuthState from '../../lib/state mangment/AuthState';
+import { useNavigate } from 'react-router-dom';
+
+function useGetQuery(key: string, url: string , params:any={},options:any={}) {
+ const axios = useAxios();
+ const {logout} = useAuthState()
+ const navigate = useNavigate()
+ return useQuery(
+ params ? [key, params] : key,
+ async () => {
+ const response = await axios.get(url , {params});
+ return response.data;
+ },
+
+
+ {
+ onError: (error:any) => {
+ console.log('====================================');
+ console.log(error.response.status);
+ console.log('====================================');
+ if(error.response.status == 401 || error.response.status == 403){
+ logout()
+ navigate("/auth")
+
+
+ }
+
+ },
+ refetchOnWindowFocus: false,
+
+ ...options
+
+ }
+ );
+}
+
+export default useGetQuery;
diff --git a/src/api/helper/useGetSingleQuery.ts b/src/api/helper/useGetSingleQuery.ts
new file mode 100644
index 0000000..e930dc7
--- /dev/null
+++ b/src/api/helper/useGetSingleQuery.ts
@@ -0,0 +1,38 @@
+import { useQuery } from 'react-query';
+import useAxios from './useAxios';
+import useAuthState from '../../lib/state mangment/AuthState';
+import { useNavigate, useParams } from 'react-router-dom';
+
+function useGetSingleQuery(key: string, url: string , params:any={},options:any={}) {
+ const axios = useAxios();
+ const {logout} = useAuthState()
+ const language = localStorage.getItem("language") ?? "en"
+ const navigate = useNavigate()
+ const {id} = useParams()
+
+ return useQuery(
+ [id, key,params?.id],
+ async () => {
+ const response = await axios.get(url+"?"+params?.name+"="+params?.id+`?lang=${language}`);
+ return response.data;
+ },
+
+
+ {
+ onError: (error:any) => {
+ if(error.response.status == 401 || error.response.status == 403){
+ logout()
+ navigate("/auth")
+
+ }
+
+ },
+ refetchOnWindowFocus: false,
+
+ ...options
+
+ }
+ );
+}
+
+export default useGetSingleQuery;
diff --git a/src/api/helper/useGetWithFillter.ts b/src/api/helper/useGetWithFillter.ts
new file mode 100644
index 0000000..448e548
--- /dev/null
+++ b/src/api/helper/useGetWithFillter.ts
@@ -0,0 +1,22 @@
+import { useQuery } from 'react-query';
+import useAxios from './useAxios';
+
+export default function useGetQueryPagination(KEY: string | string[], Api: string, options: any = {}) {
+ const axios = useAxios();
+ const pagination = options;
+
+ return useQuery(
+ [ KEY], async () => {
+ const response = await axios.get(Api + pagination );
+ return response.data;
+ },
+ {
+ onError: (error:any) => {
+
+ },
+
+
+ }
+ );
+}
+
diff --git a/src/api/helper/useToggleStatus.ts b/src/api/helper/useToggleStatus.ts
new file mode 100644
index 0000000..0ef86bb
--- /dev/null
+++ b/src/api/helper/useToggleStatus.ts
@@ -0,0 +1,32 @@
+import { useQueryClient, useMutation } from "react-query";
+import { toast } from "react-toastify";
+import { useTranslation } from "react-i18next";
+import useAxios from "./useAxios";
+
+export const useToggleStatus = (key:any, url:any, object_id:any) => {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const [t] = useTranslation();
+
+ return useMutation(
+ async ({ id, new_status }:any) => {
+ const { data } = await axios.post(url, {
+ [object_id]: id,
+ new_status,
+ });
+ return { ...data, id, new_status };
+ },
+ {
+ onSuccess: ({ message, id, new_status }) => {
+ toast.success(message || t("toggle_success"));
+
+ queryClient.invalidateQueries([key]);
+ },
+ onError: (err:any) => {
+ const message = err?.response?.data?.message || t("toggle_failed");
+ toast.error(message);
+ // validateSession(err.response);
+ },
+ }
+ );
+};
diff --git a/src/api/helper/useUpdateMutation.ts b/src/api/helper/useUpdateMutation.ts
new file mode 100644
index 0000000..cc5049b
--- /dev/null
+++ b/src/api/helper/useUpdateMutation.ts
@@ -0,0 +1,53 @@
+import { useQueryClient, useMutation, UseMutationResult } from "react-query";
+import { toast } from "react-toastify";
+import useAxios from "./useAxios";
+import { useTranslation } from "react-i18next";
+import { useParams } from "react-router-dom";
+
+type AxiosResponse = {
+ message: string;
+ // Add other properties as needed
+};
+
+const useUpdateMutation = (
+ key: string,
+ url: string,
+ toastMessage: boolean = false,
+ method?:string
+): UseMutationResult => {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const [t] = useTranslation();
+ const {id}= useParams()
+
+ return useMutation(
+ async (dataToSend) => {
+
+ const { data } = await axios.post(url+"/"+id, dataToSend,{
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ });
+ return data;
+
+
+ },
+ {
+ onSuccess: (data) => {
+ if (toastMessage) {
+ toast.success(data.message || t("updated_successfully"));
+ }
+ queryClient.invalidateQueries([key]);
+ },
+ onError: (err:any) => {
+ const message = err?.response?.data?.message || t("failed_to_update_data");
+ toast.error(message);
+
+
+ // validateSession(err.response);
+ },
+ }
+ );
+};
+
+export default useUpdateMutation;
diff --git a/src/api/helper/useUpdateMutationById.ts b/src/api/helper/useUpdateMutationById.ts
new file mode 100644
index 0000000..1d5ed72
--- /dev/null
+++ b/src/api/helper/useUpdateMutationById.ts
@@ -0,0 +1,57 @@
+import { useQueryClient, useMutation, UseMutationResult } from "react-query";
+import { toast } from "react-toastify";
+import useAxios from "./useAxios";
+import { useTranslation } from "react-i18next";
+import { useParams } from "react-router-dom";
+
+type AxiosResponse = {
+ message: string;
+ // Add other properties as needed
+};
+
+const useUpdateMutationById = (
+ key: string,
+ url: string,
+ toastMessage: boolean = false,
+ method?:string
+): UseMutationResult => {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const [t] = useTranslation();
+
+ return useMutation(
+ async (dataToSend:any) => {
+ if(method === "put"){
+ const { data } = await axios.put(url+"/"+dataToSend?.id, dataToSend );
+ return data;
+ }else{
+ const { data } = await axios.post(url+"/"+dataToSend?.id, dataToSend,{
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ });
+ return data;
+ }
+
+
+
+ },
+ {
+ onSuccess: (data) => {
+ if (toastMessage) {
+ toast.success(data.message || t("updated_successfully"));
+ }
+ queryClient.invalidateQueries([key]);
+ },
+ onError: (err:any) => {
+ const message = err?.response?.data?.message || t("failed_to_update_data");
+ toast.error(message);
+
+
+ // validateSession(err.response);
+ },
+ }
+ );
+};
+
+export default useUpdateMutationById;
diff --git a/src/api/helper/useUpdateMutationPut.ts b/src/api/helper/useUpdateMutationPut.ts
new file mode 100644
index 0000000..bac1190
--- /dev/null
+++ b/src/api/helper/useUpdateMutationPut.ts
@@ -0,0 +1,52 @@
+import { useQueryClient, useMutation, UseMutationResult } from "react-query";
+import { toast } from "react-toastify";
+import useAxios from "./useAxios";
+import { useTranslation } from "react-i18next";
+import { useParams } from "react-router-dom";
+
+type AxiosResponse = {
+ message: string;
+ // Add other properties as needed
+};
+
+const useUpdateMutationPost = (
+ key: string,
+ url: string,
+ toastMessage: boolean = true,
+ method?:string
+): UseMutationResult => {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const [t] = useTranslation();
+ const {id}= useParams()
+
+ return useMutation(
+ async (dataToSend) => {
+
+ const { data } = await axios.post(url+"/"+id, dataToSend,{
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ });
+ return data;
+
+ },
+ {
+ onSuccess: (data) => {
+ if (toastMessage) {
+ toast.success(data.message || t("updated_successfully"));
+ }
+ queryClient.invalidateQueries([key]);
+ },
+ onError: (err:any) => {
+ const message = err?.response?.data?.message || t("failed_to_update_data");
+ toast.error(message);
+
+
+ // validateSession(err.response);
+ },
+ }
+ );
+};
+
+export default useUpdateMutationPost;
diff --git a/src/api/helper/useUploadWithProgress.ts b/src/api/helper/useUploadWithProgress.ts
new file mode 100644
index 0000000..00db02a
--- /dev/null
+++ b/src/api/helper/useUploadWithProgress.ts
@@ -0,0 +1,75 @@
+import { useState } from "react";
+import { useQueryClient, useMutation, MutationFunction } from "react-query";
+import { toast } from "react-toastify";
+import useAxios from "./useAxios";
+import { AxiosResponse } from "axios";
+import { useTranslation } from "react-i18next";
+import { QueryStatusEnum } from "../../config/QueryStatus";
+// import { validateSession } from "./validateSession";
+
+interface UploadWithProgressReturnType {
+ percentCompleted: number;
+ mutate: MutationFunction;
+ isLoading: boolean;
+ isError: boolean;
+ error: unknown;
+ isSuccess:boolean,
+ value:any,
+ status : QueryStatusEnum
+}
+
+export const useUploadWithProgress = (
+ key: string,
+ url: string
+): UploadWithProgressReturnType => {
+ const axios = useAxios();
+ const queryClient = useQueryClient();
+ const [percentCompleted, setPercentCompleted] = useState(0.0);
+ const {t} = useTranslation();
+ const mutation = useMutation<
+ AxiosResponse,
+ unknown,
+ any,
+ {
+ onSuccess: (data: AxiosResponse) => void;
+ onError: (error: unknown) => void;
+ }
+ >(
+ async (dataToSend) => {
+ setPercentCompleted(0.0);
+ const { data } = await axios.post(url, dataToSend, {
+ onUploadProgress: (event:any) => {
+ console.log();
+
+ if (event?.event?.lengthComputable) {
+ setPercentCompleted(Math.round((event.loaded * 100) / event.total));
+ }
+ },
+ });
+ return data;
+ },
+ {
+ onSuccess: ({ data }) => {
+ toast.success(data.message || t("_messages.success.upload"));
+ queryClient.invalidateQueries([key]);
+ },
+ onError: (err:any) => {
+ const message =
+ err?.response?.data?.message || t("_messages.error.upload");
+ toast.error(message);
+ // validateSession(err.response);
+ },
+ }
+ );
+
+ return {
+ percentCompleted,
+ value:percentCompleted,
+ mutate: mutation.mutate as MutationFunction,
+ isLoading: mutation.isLoading,
+ isError: mutation.isError,
+ error: mutation.error,
+ isSuccess :mutation.isSuccess,
+ status : mutation.status as QueryStatusEnum
+ };
+};
\ No newline at end of file
diff --git a/src/asset/logo/MainLogo.png b/src/asset/logo/MainLogo.png
new file mode 100644
index 0000000..84d4dcb
Binary files /dev/null and b/src/asset/logo/MainLogo.png differ
diff --git a/src/config/AppKey.ts b/src/config/AppKey.ts
new file mode 100644
index 0000000..1a3da71
--- /dev/null
+++ b/src/config/AppKey.ts
@@ -0,0 +1,12 @@
+
+
+
+const PROJECT_NAME = "Point_DAHBOARD"
+
+export const TOKEN_KEY = PROJECT_NAME + "_TOKEN"
+export const TOKEN_KEY_SOCKET = PROJECT_NAME + "_SOKCET_TOKEN"
+
+export const USER_KEY = PROJECT_NAME + "_USER"
+
+
+/// 1825|laravel_sanctum_RpRqXDf1jg1Jgb0VjnJcUzPpSmX46PD7h8jB8ag372d0778a
diff --git a/src/config/QueryStatus.ts b/src/config/QueryStatus.ts
new file mode 100644
index 0000000..2351251
--- /dev/null
+++ b/src/config/QueryStatus.ts
@@ -0,0 +1,8 @@
+
+
+export enum QueryStatusEnum {
+ LOADING="loading",
+ ERROR ="error",
+ SUCCESS="success",
+ IDLE ="idle"
+}
diff --git a/src/config/RoleConfige.ts b/src/config/RoleConfige.ts
new file mode 100644
index 0000000..b445160
--- /dev/null
+++ b/src/config/RoleConfige.ts
@@ -0,0 +1,7 @@
+export const VIEWER: string = "viewer";
+export const VENDOR: string = "vendor";
+export const ADMIN: string = "admin";
+export const SUPER_ADMIN: string = "Super Admin";
+export const CLIENT: string = "client";
+
+export const Roles: string[] = [VIEWER, VENDOR, ADMIN, SUPER_ADMIN];
\ No newline at end of file
diff --git a/src/enums/ChartTypeEnum.ts b/src/enums/ChartTypeEnum.ts
new file mode 100644
index 0000000..79a6c3e
--- /dev/null
+++ b/src/enums/ChartTypeEnum.ts
@@ -0,0 +1,14 @@
+export enum ChartTypeEnum {
+ LINE = "line",
+ AREA = "area",
+ BAR = "bar",
+ RADIAL = "radialBar",
+ PIE = "pie",
+ DONUT = "donut",
+ SCATTER = "scatter",
+ BUBBLE = "bubble",
+ HEATMAP = "heatmap",
+ CANDLESTICK = "candlestick",
+ }
+
+
\ No newline at end of file
diff --git a/src/enums/SocketEventEnum.ts b/src/enums/SocketEventEnum.ts
new file mode 100644
index 0000000..bcded09
--- /dev/null
+++ b/src/enums/SocketEventEnum.ts
@@ -0,0 +1,15 @@
+
+
+
+export enum SocketEventLisntEnum {
+
+ SOCKET_DEBUG = 'dashboard_debug' ,
+ SOCKET_NEW_USER = 'new_driver_come_online' ,
+ SOCKET_UPDATE_USER = 'update_driver_online' ,
+ SOCKET_REMOVE_USER = 'remove_driver_from_online' ,
+
+ SOCKET_NEW_ORDER = 'new_order_come_pendding' ,
+ SOCKET_ACCEPTE_ORDER = 'order_accepted_by_driver' ,
+ SOCKET_START_ORDER = 'order_start' ,
+
+}
\ No newline at end of file
diff --git a/src/index.tsx b/src/index.tsx
new file mode 100644
index 0000000..28bfafa
--- /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..4b56401
--- /dev/null
+++ b/src/lib/ReactQueryProvider.tsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import { QueryClient, QueryClientProvider } from 'react-query'
+
+function QueryProvider({ children }: any) {
+ const queryClient = new QueryClient()
+
+ return (
+
+ {children}
+
+
+ )
+}
+
+export default QueryProvider
+
+
diff --git a/src/lib/SocketProvider.tsx b/src/lib/SocketProvider.tsx
new file mode 100644
index 0000000..aa00e9d
--- /dev/null
+++ b/src/lib/SocketProvider.tsx
@@ -0,0 +1,37 @@
+
+import { Socket, io } from 'socket.io-client';
+import { TOKEN_KEY_SOCKET } from '../config/AppKey';
+
+
+export const BASE_URL_SOCKET = 'http://192.168.1.14:8001/';
+var socket :Socket | null = null ;
+
+
+function InitSocket(){
+
+
+
+ if (!socket){
+ socket = io(BASE_URL_SOCKET , {
+ transports:['websocket'],
+ autoConnect:true,
+ query:{
+ token:localStorage.getItem(TOKEN_KEY_SOCKET),
+
+ }
+ });
+ }
+}
+
+export const disconnectSocket = ()=>{
+
+ socket?.disconnect();
+ socket = null;
+}
+export const getScoket = ()=>{
+
+ InitSocket();
+ return socket;
+}
+
+
diff --git a/src/lib/ToastProvider.tsx b/src/lib/ToastProvider.tsx
new file mode 100644
index 0000000..b2e9c27
--- /dev/null
+++ b/src/lib/ToastProvider.tsx
@@ -0,0 +1,27 @@
+import React from 'react'
+import { ToastContainer } from 'react-toastify'
+import 'react-toastify/dist/ReactToastify.css';
+
+function ToastProvider({ children }: any) {
+ let What_the_language = localStorage.getItem('language') ?? "en";
+
+ return (
+ <>
+
+ {children}
+ >
+ )
+}
+
+export default ToastProvider
\ No newline at end of file
diff --git a/src/lib/state mangment/AuthState.ts b/src/lib/state mangment/AuthState.ts
new file mode 100644
index 0000000..b2bd147
--- /dev/null
+++ b/src/lib/state mangment/AuthState.ts
@@ -0,0 +1,51 @@
+import {create} from 'zustand';
+import { TOKEN_KEY, TOKEN_KEY_SOCKET, USER_KEY } from '../../config/AppKey';
+
+interface LoginResponse {
+ token:string ,
+ "admin": any,
+ token_node:string
+}
+
+interface AuthStore {
+ user: any | null |undefined;
+ token:string |null | undefined;
+ isAuthenticated: boolean;
+ login: (userData: LoginResponse) => Promise;
+ logout: () => Promise;
+}
+
+const useAuthState = create((set) => {
+
+ const storedUser :any = localStorage.getItem(USER_KEY) ;
+
+ const storedToken = localStorage.getItem(TOKEN_KEY);
+ const initialUser = (storedUser && storedUser !== 'undefined') ? JSON.parse(storedUser) : null;
+
+ return {
+ user: initialUser,
+ isAuthenticated: !!storedToken,
+ token:storedToken,
+ login: async (userData) => {
+ console.log(userData);
+ localStorage.setItem(TOKEN_KEY , userData.token)
+
+ localStorage.setItem(USER_KEY , JSON.stringify(userData.admin))
+
+ set((state)=>({user:userData.admin , isAuthenticated:true , token:userData.token}))
+
+ },
+ logout: async () => {
+
+ localStorage.removeItem(TOKEN_KEY )
+ localStorage.removeItem(TOKEN_KEY_SOCKET )
+
+ localStorage.removeItem(USER_KEY )
+ set((state)=>({user:null , isAuthenticated:false , token:null}))
+
+
+ },
+ };
+});
+
+export default useAuthState;
diff --git a/src/lib/state mangment/LayoutPagestate.ts b/src/lib/state mangment/LayoutPagestate.ts
new file mode 100644
index 0000000..db1c4b5
--- /dev/null
+++ b/src/lib/state mangment/LayoutPagestate.ts
@@ -0,0 +1,29 @@
+import {create} from 'zustand'
+
+interface ModelState {
+ isOpenAddModel: boolean;
+ isOpenEditModel: boolean;
+ objectToEdit: any;
+ isThemChanged:any;
+ setThemChange :()=> void ;
+ setIsOpenAddModel: () => void;
+ setIsOpenEditModel: () => void;
+ CloseAllModal: () => void;
+ setObjectToEdit: (data: any) => void;
+}
+
+export const usePageState = create((set) => ({
+ isOpenAddModel: false,
+ isOpenEditModel: false,
+ objectToEdit: null,
+ isThemChanged:false,
+ setThemChange: () =>
+ set((state) => ({ isThemChanged: !state.isThemChanged })),
+ setIsOpenAddModel: () =>
+ set((state) => ({ isOpenAddModel: !state.isOpenAddModel })),
+ setIsOpenEditModel: () =>
+ set((state) => ({ isOpenEditModel: !state.isOpenEditModel })),
+ CloseAllModal: () =>
+ set((state) => ({ isOpenAddModel: false, isOpenEditModel: false })),
+ setObjectToEdit: (data) => set(() => ({ objectToEdit: data })),
+}));
diff --git a/src/lib/state mangment/Pages/Products.ts b/src/lib/state mangment/Pages/Products.ts
new file mode 100644
index 0000000..4679b15
--- /dev/null
+++ b/src/lib/state mangment/Pages/Products.ts
@@ -0,0 +1,15 @@
+import {create} from 'zustand'
+
+interface ProductState {
+ TapItems:any;
+ setTapItems :any ;
+ TapItemValues:any;
+ setTapItemValues :any ;
+}
+
+export const useProductVarianState = create((set) => ({
+ TapItems:[],
+ setTapItems: (data : any) => set(() => ({ TapItems: data })),
+ TapItemValues:[],
+ setTapItemValues: (data : any) => set(() => ({ TapItemValues: data })),
+}));
diff --git a/src/lib/state mangment/driver&customer/ModelState.tsx b/src/lib/state mangment/driver&customer/ModelState.tsx
new file mode 100644
index 0000000..4a4ee9c
--- /dev/null
+++ b/src/lib/state mangment/driver&customer/ModelState.tsx
@@ -0,0 +1,33 @@
+import {create} from 'zustand'
+
+interface ModalState {
+
+ isOpenBlock:boolean ,
+ isOpenGift:boolean ,
+ isOpenUnBlock:boolean ,
+
+ setIsopenBlock :() => void ,
+ setIsopenUnBlock :() => void ,
+ setIsopenGift :() => void ,
+
+ setObjectId :(data:number) => void ,
+ objectID:number
+
+}
+
+export const useCommonModelState = create((set) => ({
+
+ isOpenBlock:false,
+ isOpenGift:false,
+ isOpenUnBlock:false,
+
+ setIsopenBlock: () =>
+ set((state) => ({ isOpenBlock: !state.isOpenBlock })),
+ setIsopenUnBlock: () =>
+ set((state) => ({ isOpenUnBlock: !state.isOpenUnBlock })),
+ setIsopenGift: () =>
+ set((state) => ({ isOpenGift: !state.isOpenGift })),
+ setObjectId: (data:number) =>
+ set((state) => ({ objectID: data })),
+ objectID:0
+}));
diff --git a/src/translate/ar.json b/src/translate/ar.json
new file mode 100644
index 0000000..1cf493f
--- /dev/null
+++ b/src/translate/ar.json
@@ -0,0 +1,40 @@
+{
+ "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": "وضع اليلي",
+ "reset": "إعادة تعيين",
+ "submit": "إرسال",
+ "errorPage": {
+ "networkError": "خطأ في الشبكة",
+ "checkAndModify": "يرجى التحقق من الشبكة الخاصة بك وإعادة تحميل الصفحة.",
+ "refetch": "إعادة تحميل الصفحة",
+ "goToHome": "الانتقال إلى الصفحة الرئيسية"
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/src/translate/en.json b/src/translate/en.json
new file mode 100644
index 0000000..fb7ad8f
--- /dev/null
+++ b/src/translate/en.json
@@ -0,0 +1,33 @@
+{
+ "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",
+ "reset": "Reset",
+ "submit": "Submit",
+ "errorPage": {
+ "networkError": "Network Error",
+ "checkAndModify": "Please check your network and refetch the page.",
+ "refetch": "Refetch Page",
+ "goToHome": "Go to Home"
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/translate/text b/src/translate/text
new file mode 100644
index 0000000..e69de29
diff --git a/src/types/SocketEvent.ts b/src/types/SocketEvent.ts
new file mode 100644
index 0000000..55b613f
--- /dev/null
+++ b/src/types/SocketEvent.ts
@@ -0,0 +1,8 @@
+
+
+export interface SocketDashboardDebugDataEvent {
+ event :string ,
+ socket_id :string ,
+ room ?: string | null ,
+ data : any
+}
\ No newline at end of file
diff --git a/src/types/User.ts b/src/types/User.ts
new file mode 100644
index 0000000..e8c3788
--- /dev/null
+++ b/src/types/User.ts
@@ -0,0 +1,21 @@
+
+export interface IUser{
+ "id": number ,
+ "full_name": string ,
+ "email": string ,
+ "phone": string ,
+ "is_verified": number,
+ "created_at": string ,
+ "updated_at": string,
+ "stripe_id": any,
+ "pm_type": any,
+ "pm_last_four": any,
+ "trial_ends_at": any,
+ "user_uid": any,
+ "sms_code": any,
+ "messageID": any,
+ "insurance_amount": number ,
+ "insurance_payment_id": any,
+ "role_type": string
+
+}
\ No newline at end of file
diff --git a/src/utils/Array/ArrayToObjectFormik.ts b/src/utils/Array/ArrayToObjectFormik.ts
new file mode 100644
index 0000000..5c11d90
--- /dev/null
+++ b/src/utils/Array/ArrayToObjectFormik.ts
@@ -0,0 +1,26 @@
+export function objectToArray(obj:any) {
+ // Initialize an empty array to store the result
+ const result = [] as any ;
+
+ // Iterate over the keys of the object
+ for (const key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ // Extract the index from the key
+ const index = parseInt(key.split('.')[0]);
+
+ // Get the attribute name from the key
+ const attributeName = key.split('.')[1];
+
+ // If the index does not exist in the result array, create a new object
+ if (!result[index]) {
+ result[index] = {};
+ }
+
+
+ // Set the attribute value in the result object
+ result[index][attributeName] = obj[key];
+ }
+ }
+
+ return result;
+ }
\ No newline at end of file
diff --git a/src/utils/Array/changeShapeInfo.tsx b/src/utils/Array/changeShapeInfo.tsx
new file mode 100644
index 0000000..0908eb2
--- /dev/null
+++ b/src/utils/Array/changeShapeInfo.tsx
@@ -0,0 +1,14 @@
+export function changeShapeInfo(originalObject: any) {
+ const transformedObject: any = {};
+
+ for (const key in originalObject) {
+ if (originalObject.hasOwnProperty(key)) {
+ const index = key.split('.')[0]; // Extract index from key
+ const attribute = key.split('.')[1]; // Extract attribute from key
+
+ transformedObject[originalObject[`${index}.key`]] = originalObject[`${index}.Description`];
+ }
+ }
+
+ return transformedObject
+}
\ No newline at end of file
diff --git a/src/utils/Array/filterUndefinedAndEmpty.ts b/src/utils/Array/filterUndefinedAndEmpty.ts
new file mode 100644
index 0000000..c0982ce
--- /dev/null
+++ b/src/utils/Array/filterUndefinedAndEmpty.ts
@@ -0,0 +1,5 @@
+const filterUndefinedAndEmpty = (array:any) => {
+ return array?.filter((data:any) => data !== undefined && Object.keys(data).length !== 0);
+ };
+
+ export default filterUndefinedAndEmpty;
\ No newline at end of file
diff --git a/src/utils/Array/getInfoKeyAndDescriptions.ts b/src/utils/Array/getInfoKeyAndDescriptions.ts
new file mode 100644
index 0000000..8ff163f
--- /dev/null
+++ b/src/utils/Array/getInfoKeyAndDescriptions.ts
@@ -0,0 +1,12 @@
+export function convertToObject(obj:any) {
+ const newObj = {} as any;
+ for (const key in obj) {
+ if (key.includes('.Key')) {
+ const newKey = obj[key];
+ const valueKey = key.replace('.Key', '.Description');
+ const value = obj[valueKey];
+ newObj[newKey] = value;
+ }
+ }
+ return newObj;
+}
\ No newline at end of file
diff --git a/src/utils/Date/ChangeFormat.ts b/src/utils/Date/ChangeFormat.ts
new file mode 100644
index 0000000..311775f
--- /dev/null
+++ b/src/utils/Date/ChangeFormat.ts
@@ -0,0 +1,5 @@
+export function ChangeformatDate(dateString:string) {
+ const dateObject = new Date(dateString);
+ const formattedDate = `${dateObject.toLocaleDateString()} ${dateObject.toLocaleTimeString()}`;
+ return formattedDate;
+}
\ No newline at end of file
diff --git a/src/utils/colors/getPrimaryColor.ts b/src/utils/colors/getPrimaryColor.ts
new file mode 100644
index 0000000..4f86548
--- /dev/null
+++ b/src/utils/colors/getPrimaryColor.ts
@@ -0,0 +1,3 @@
+
+
+export const getPrimaryColor = ()=>getComputedStyle(document.querySelector(':root')as any )?.getPropertyValue('--primary')
diff --git a/src/utils/language/mapTranslatedProperties.tsx b/src/utils/language/mapTranslatedProperties.tsx
new file mode 100644
index 0000000..e91b645
--- /dev/null
+++ b/src/utils/language/mapTranslatedProperties.tsx
@@ -0,0 +1,27 @@
+export const mapTranslatedProperties = (
+ arrayOfDetails :any,
+ properties:any ,
+ language_id : '1'|'2' |1 |2
+ ) => {
+ if (!arrayOfDetails || !properties || !language_id) return "";
+ if (Array.isArray(arrayOfDetails) && arrayOfDetails.length === 0) return "";
+
+ const target = arrayOfDetails.find(
+ (item:any) => item.language_id === language_id
+ );
+ if (!target) {
+ return "";
+ }
+
+ if (!Array.isArray(properties)) {
+ return target[properties];
+ }
+
+ // [prop1, prop2, prop3, ....] is passed
+ const ret:any = {};
+ properties.forEach((prop:string) => {
+ ret[prop] = target[prop];
+ });
+ return ret;
+ };
+
\ No newline at end of file
diff --git a/src/zustand/Modal.ts b/src/zustand/Modal.ts
new file mode 100644
index 0000000..97cd522
--- /dev/null
+++ b/src/zustand/Modal.ts
@@ -0,0 +1,15 @@
+import {create} from 'zustand'
+
+interface ModalState {
+ isOpen: boolean;
+ setIsOpen: (value:boolean) => void;
+
+}
+
+
+export const useModalState = create((set) => ({
+ isOpen: false,
+ setIsOpen: () =>
+ set((state) => ({ isOpen: !state.isOpen })),
+
+}));
diff --git a/src/zustand/OrderFillter.ts b/src/zustand/OrderFillter.ts
new file mode 100644
index 0000000..6c6e6bf
--- /dev/null
+++ b/src/zustand/OrderFillter.ts
@@ -0,0 +1,50 @@
+import { create } from 'zustand';
+
+interface ModalState {
+ username: string | null;
+ coupon: string | null;
+ state: string | null;
+ fromDate: Date | null;
+ toDate: Date | null;
+ totalFrom: number | null;
+ totalTo: number | null;
+ setUsername: (value: string | null) => void;
+ setCoupon: (value: string | null) => void;
+ setstate: (value: string | null) => void;
+ setFromDate: (value: Date | null) => void;
+ setToDate: (value: Date | null) => void;
+ setTotalFrom: (value: number | null) => void;
+ setTotalTo: (value: number | null) => void;
+ reset: () => void;
+}
+
+export const useOrderFillterState = create((set) => {
+
+ return {
+ username: null,
+ coupon: null,
+ state: null,
+ fromDate: null,
+ toDate: null,
+ totalFrom: null,
+ totalTo: null,
+ setUsername: (value) => set((state) => ({ ...state, username: value })),
+ setCoupon: (value) => set((state) => ({ ...state, coupon: value })),
+ setstate: (value) => set((state) => ({ ...state, state: value })),
+ setFromDate: (value) => set((state) => ({ ...state, fromDate: value })),
+ setToDate: (value) => set((state) => ({ ...state, toDate: value })),
+ setTotalFrom: (value) => set((state) => ({ ...state, totalFrom: value })),
+ setTotalTo: (value) => set((state) => ({ ...state, totalTo: value })),
+ reset: () => {
+ set({
+ username: null,
+ coupon: null,
+ fromDate: null,
+ toDate: null,
+ totalFrom: null,
+ totalTo: null,
+ state:null
+ });
+ },
+ };
+});
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..a273b0c
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx"
+ },
+ "include": [
+ "src"
+ ]
+}