update the dashbord and router
871
package-lock.json
مولّد
@@ -1,15 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "front-end-my-resturant",
|
"name": "resturant-dashBord",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.14.0",
|
||||||
|
"@emotion/styled": "^11.14.0",
|
||||||
|
"@mui/icons-material": "^7.1.0",
|
||||||
|
"@mui/material": "^7.1.0",
|
||||||
"@testing-library/dom": "^10.4.0",
|
"@testing-library/dom": "^10.4.0",
|
||||||
"@testing-library/jest-dom": "^6.6.3",
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
"@testing-library/react": "^16.3.0",
|
"@testing-library/react": "^16.3.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
|
"react-circular-progressbar": "^2.2.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
|
"react-router-dom": "^7.6.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
|
"recharts": "^2.15.3",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
ثنائية
public/favicon.ico
|
قبل العرض: | الارتفاع: | الحجم: 3.8 KiB |
ثنائية
public/fonts/PlusJakartaSans/PlusJakartaSans-Medium.ttf
Normal file
ثنائية
public/fonts/PlusJakartaSans/PlusJakartaSans-Regular.ttf
Normal file
ثنائية
public/fonts/PlusJakartaSans/PlusJakartaSans-SemiBold.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-Black.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-BlackItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-Bold.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-BoldItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-ExtraBold.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-ExtraBoldItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-ExtraLight.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-ExtraLightItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-Italic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-Light.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-LightItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-Medium.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-MediumItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-Regular.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-SemiBold.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-SemiBoldItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-Thin.ttf
Normal file
ثنائية
public/fonts/inter/Inter_18pt-ThinItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-Black.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-BlackItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-Bold.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-BoldItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-ExtraBold.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-ExtraBoldItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-ExtraLight.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-ExtraLightItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-Italic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-Light.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-LightItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-Medium.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-MediumItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-Regular.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-SemiBold.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-SemiBoldItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-Thin.ttf
Normal file
ثنائية
public/fonts/inter/Inter_24pt-ThinItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-Black.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-BlackItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-Bold.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-BoldItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-ExtraBold.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-ExtraBoldItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-ExtraLight.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-ExtraLightItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-Italic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-Light.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-LightItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-Medium.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-MediumItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-Regular.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-SemiBold.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-SemiBoldItalic.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-Thin.ttf
Normal file
ثنائية
public/fonts/inter/Inter_28pt-ThinItalic.ttf
Normal file
ثنائية
public/icon.ico
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 7.8 KiB |
ثنائية
public/image.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 6.2 KiB |
ثنائية
public/images/compeoter.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 24 KiB |
ثنائية
public/images/hand.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 55 KiB |
ثنائية
public/images/icons/email.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 2.4 KiB |
ثنائية
public/images/icons/image.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 6.6 KiB |
ثنائية
public/images/icons/key.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 3.0 KiB |
ثنائية
public/images/icons/pen.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 3.6 KiB |
ثنائية
public/images/icons/rocket.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 4.3 KiB |
ثنائية
public/images/waiterss2.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 44 KiB |
ثنائية
public/images/waiterss4.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 45 KiB |
ثنائية
public/images/waitress.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 1.2 MiB |
ثنائية
public/images/waitress3.png
Normal file
|
بعد العرض: | الارتفاع: | الحجم: 47 KiB |
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="/image.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
@@ -10,34 +10,19 @@
|
|||||||
content="Web site created using create-react-app"
|
content="Web site created using create-react-app"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<!--
|
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
|
||||||
-->
|
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
|
||||||
<!--
|
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
|
||||||
Only files inside the `public` folder can be referenced from the HTML.
|
|
||||||
|
|
||||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
<style>
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
* {
|
||||||
-->
|
margin: 0
|
||||||
<title>React App</title>
|
}
|
||||||
|
</style>
|
||||||
|
<title>Restaurant</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<!--
|
|
||||||
This HTML file is a template.
|
|
||||||
If you open it directly in the browser, you will see an empty page.
|
|
||||||
|
|
||||||
You can add webfonts, meta tags, or analytics to this file.
|
|
||||||
The build step will place the bundled scripts into the <body> tag.
|
|
||||||
|
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
|
||||||
-->
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
86
src/App.css
@@ -22,6 +22,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: calc(10px + 2vmin);
|
font-size: calc(10px + 2vmin);
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-link {
|
.App-link {
|
||||||
@@ -36,3 +37,88 @@
|
|||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* CUSTOM FONTS */
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: INTER;
|
||||||
|
src: url('../public/fonts/inter/Inter_18pt-Thin.ttf');
|
||||||
|
font-weight: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: INTER;
|
||||||
|
src: url('../public/fonts/inter/Inter_18pt-ExtraLight.ttf');
|
||||||
|
font-weight: 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: INTER;
|
||||||
|
src: url('../public/fonts/inter/Inter_18pt-Light.ttf');
|
||||||
|
font-weight: 300;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: INTER;
|
||||||
|
src: url('../public/fonts/inter/Inter_18pt-Regular.ttf');
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: INTER;
|
||||||
|
src: url('../public/fonts/inter/Inter_18pt-Medium.ttf');
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: INTER;
|
||||||
|
src: url('../public/fonts/inter/Inter_18pt-SemiBold.ttf');
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: INTER;
|
||||||
|
src: url('../public/fonts/inter/Inter_18pt-Bold.ttf');
|
||||||
|
font-weight: 700;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: INTER;
|
||||||
|
src: url('../public/fonts/inter/Inter_18pt-ExtraBold.ttf');
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: INTER;
|
||||||
|
src: url('../public/fonts/inter/Inter_18pt-Black.ttf');
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: PlusJakartaSans ;
|
||||||
|
src: url('../public/fonts/PlusJakartaSans/PlusJakartaSans-Medium.ttf');
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: PlusJakartaSans ;
|
||||||
|
src: url('../public/fonts/PlusJakartaSans/PlusJakartaSans-SemiBold.ttf');
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: PlusJakartaSans ;
|
||||||
|
src: url('../public/fonts/PlusJakartaSans/PlusJakartaSans-Regular.ttf');
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
/* === CUSTOM FONTS ===*/
|
||||||
|
|
||||||
|
|||||||
58
src/App.js
@@ -1,24 +1,48 @@
|
|||||||
import logo from './logo.svg';
|
import React from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
import { ThemeProvider } from '@mui/material/styles';
|
||||||
|
import theme from './theme';
|
||||||
|
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
||||||
|
|
||||||
|
import LoginForm from './components/Authentication/SignUp_In/LoginForm';
|
||||||
|
import RegisterForm from './components/Authentication/SignUp_In/RegisterForm';
|
||||||
|
import ForgetPassword from './components/Authentication/ForgetPassword/ForgetFormMain';
|
||||||
|
|
||||||
|
|
||||||
|
import Dashboard from './components/Home/Dashboard/Dashboard';
|
||||||
|
import Inventory from './components/Home/Inventory/Inventory';
|
||||||
|
import Analytics from './components/Home/Analytics&Reporting/Analytics';
|
||||||
|
import Supplier from './components/Home/Supplier/Supplier';
|
||||||
|
import Cashier from './components/Home/Cashier/Cashier';
|
||||||
|
import CreateYourRestaurant from './components/Home/CreateYourRestaurant/CreateRestaurant';
|
||||||
|
|
||||||
|
import Training from './components/Home/Training/Training';
|
||||||
|
import RestaurantProfile from './components/Home/RestaurantProfile/RestaurantProfile';
|
||||||
|
import HostKitchen from './components/Home/HostKitchen/HostKitchen';
|
||||||
|
import Settings from './components/Home/Settings/Setting';
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<ThemeProvider theme={theme}>
|
||||||
<header className="App-header">
|
<Router>
|
||||||
<img src={logo} className="App-logo" alt="logo" />
|
<Routes>
|
||||||
<p>
|
<Route path="/" element={<LoginForm />} />
|
||||||
Edit <code>src/App.js</code> and save to reload.
|
<Route path="/login" element={<LoginForm />} />
|
||||||
</p>
|
<Route path="/register" element={<RegisterForm />} />
|
||||||
<a
|
<Route path="/dashboard" element={<Dashboard />} />
|
||||||
className="App-link"
|
<Route path="/inventory" element={<Inventory />} />
|
||||||
href="https://reactjs.org"
|
<Route path="/settings" element={<Settings />} />
|
||||||
target="_blank"
|
<Route path="/profile" element={<RestaurantProfile />} />
|
||||||
rel="noopener noreferrer"
|
<Route path="/create-kitchen" element={<CreateYourRestaurant />} />
|
||||||
>
|
<Route path="/host-kitchen" element={<HostKitchen />} />
|
||||||
Learn React
|
<Route path="/cashier" element={<Cashier />} />
|
||||||
</a>
|
<Route path="/supplier" element={<Supplier />} />
|
||||||
</header>
|
<Route path="/analytics" element={<Analytics />} />
|
||||||
</div>
|
<Route path="/forget" element={<ForgetPassword />} />
|
||||||
|
<Route path="/training" element={<Training />} />
|
||||||
|
|
||||||
|
</Routes>
|
||||||
|
</Router>
|
||||||
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
132
src/components/Authentication/ForgetPassword/Congratulations.js
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Box, TextField, Typography, Button, useTheme } from '@mui/material';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
const Congratulations = ({ emailOrPhone, setEmailOrPhone }) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const theme = useTheme();
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
overflow: 'auto',
|
||||||
|
scrollbarWidth: 'none',
|
||||||
|
'&::-webkit-scrollbar': {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
|
||||||
|
mt: { xs: 4, sm: 8, md: 2 } // هامش علوي متجاوب
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: '90px',
|
||||||
|
position: 'relative',
|
||||||
|
width: 132,
|
||||||
|
height: 132,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
width: 139,
|
||||||
|
height: 139,
|
||||||
|
borderRadius: '50%',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
zIndex: 0,
|
||||||
|
backgroundColor: '#FAFAFA'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
|
||||||
|
width: 120,
|
||||||
|
height: 120,
|
||||||
|
backgroundColor: '#E9EFFF',
|
||||||
|
borderRadius: '50%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
zIndex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="/images/hand.png"
|
||||||
|
style={{ width: 60, height: 60, objectFit: 'contain' }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
</Box>
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
fontWeight={700}
|
||||||
|
marginTop={3}
|
||||||
|
marginBottom={2}
|
||||||
|
sx={{
|
||||||
|
fontSize: {
|
||||||
|
xs: '1.8rem',
|
||||||
|
sm: '2rem',
|
||||||
|
md: '2.2rem'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Congratulations!
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
fontWeight={400}
|
||||||
|
width='390px'
|
||||||
|
marginLeft='20px'
|
||||||
|
sx={{
|
||||||
|
color: '#5F6868',
|
||||||
|
fontSize: {
|
||||||
|
xs: '0.8rem',
|
||||||
|
md: '1.1rem'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Your password has been successfully updated. Thank you for choosing our service
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
|
||||||
|
{/* زر التنقل إلى صفحة تسجيل الدخول */}
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
onClick={() => navigate('/login')}
|
||||||
|
sx={{
|
||||||
|
marginTop: '20px',
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
borderRadius: '30px',
|
||||||
|
textTransform: 'none',
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '16px',
|
||||||
|
height: '52px',
|
||||||
|
padding: '12px',
|
||||||
|
maxWidth: '390px',
|
||||||
|
px: 2,
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.primary.hover,
|
||||||
|
transition: 'all 0.4s ease'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Congratulations;
|
||||||
|
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
// EmailInputSection.js
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Box, Button, TextField, Typography ,useTheme} from '@mui/material';
|
||||||
|
|
||||||
|
const EmailInputSection = ({ emailOrPhone, setEmailOrPhone }) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const [currentSlide, setCurrentSlide] = useState(0);
|
||||||
|
const slides = [0, 1, 2, 3];
|
||||||
|
|
||||||
|
const handleSend = () => {
|
||||||
|
// عملية الإرسال
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNext = () => {
|
||||||
|
if (currentSlide < slides.length - 1) {
|
||||||
|
setCurrentSlide(prev => prev + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
if (currentSlide > 0) {
|
||||||
|
setCurrentSlide(prev => prev - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box>
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src="/image.png"
|
||||||
|
alt="logo"
|
||||||
|
sx={{
|
||||||
|
width: { xs: '5vh', sm: '7vh' },
|
||||||
|
maxWidth: { xs: '40px', sm: '80px' },
|
||||||
|
height: 'auto',
|
||||||
|
objectFit: 'contain',
|
||||||
|
overflow: 'auto',
|
||||||
|
scrollbarWidth: 'none',
|
||||||
|
'&::-webkit-scrollbar': {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
fontWeight={700}
|
||||||
|
sx={{
|
||||||
|
fontSize: {
|
||||||
|
xs: '1.8rem',
|
||||||
|
sm: '2rem',
|
||||||
|
md: '2.2rem'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Forget Password
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography variant="body1" color="text.secondary">
|
||||||
|
Enter your email to reset it and regain access to your account.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Box sx={{ width: '100%', display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="black"
|
||||||
|
sx={{
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: '16px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Email/Phone
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
placeholder="Enter your email"
|
||||||
|
type="email"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
value={emailOrPhone}
|
||||||
|
onChange={(e) => setEmailOrPhone(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
'& input': {
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '15px'
|
||||||
|
},
|
||||||
|
'& input::placeholder': {
|
||||||
|
color: '#969BA7'
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: '10px',
|
||||||
|
transition: '0.3s',
|
||||||
|
'&.Mui-focused fieldset': { // أضف هذا الجزء لتغيير لون الحدود عند التركيز
|
||||||
|
borderColor: '#FF914D',
|
||||||
|
boxShadow: '0 0 0 2px rgba(255, 145, 77, 0.2)' // ظل برتقالي خفيف
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root.Mui-focused': {
|
||||||
|
borderColor: '#3f51b5',
|
||||||
|
boxShadow: '0 0 0 2px rgba(63,81,181,0.1)'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* send */}
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
onClick={handleSend}
|
||||||
|
sx={{
|
||||||
|
color:'white',
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
borderRadius: '30px',
|
||||||
|
textTransform: 'none',
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: '16px',
|
||||||
|
height: '48px',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.primary.hover ,
|
||||||
|
transition: 'all 0.4s ease'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Send
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
textAlign="center"
|
||||||
|
fontWeight={500}
|
||||||
|
sx={{
|
||||||
|
fontSize: '16px',
|
||||||
|
display: 'block',
|
||||||
|
width: '100%',
|
||||||
|
mx: 'auto',
|
||||||
|
color: '#969BA7'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
By log in, I agree to the
|
||||||
|
<a href="#" style={{ color: '#007bff', textDecoration: 'none' }}>Terms of Service</a> and
|
||||||
|
<a href="#" style={{ color: '#007bff', textDecoration: 'none' }}>Privacy Policy</a>
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EmailInputSection;
|
||||||
125
src/components/Authentication/ForgetPassword/ForgetFormMain.js
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Box, Stack ,useTheme} from '@mui/material';
|
||||||
|
import Side from './Side';
|
||||||
|
import EmailInputSection from './EmailInputSection';
|
||||||
|
import OtpVerification from './OtpVerification';
|
||||||
|
import NewPassword from './NewPassword';
|
||||||
|
import Congratulations from './Congratulations';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const ForgetForm = () => {
|
||||||
|
const [emailOrPhone, setEmailOrPhone] = useState('');
|
||||||
|
const [currentSlide, setCurrentSlide] = useState(0);
|
||||||
|
const theme = useTheme();
|
||||||
|
const slides = [
|
||||||
|
{ component: EmailInputSection, title: "Email Verification" },
|
||||||
|
{ component: OtpVerification, title: "OTP Verification" },
|
||||||
|
{ component: NewPassword, title: "New Password" },
|
||||||
|
{ component: Congratulations, title: "Congratulations" }
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleNext = () => {
|
||||||
|
if (currentSlide < slides.length - 1) {
|
||||||
|
setCurrentSlide(prev => prev + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
if (currentSlide > 0) {
|
||||||
|
setCurrentSlide(prev => prev - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const CurrentComponent = slides[currentSlide].component;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: { xs: 'column', sm: 'row' },
|
||||||
|
minHeight: '100vh',
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* ✅ Sidebar يظهر فقط من sm+ */}
|
||||||
|
<Box sx={{ width: { sm: '40%', xs: '0%' }, display: { xs: 'none', sm: 'block' } }}>
|
||||||
|
<Side currentStepIndex={currentSlide} onNext={handleNext} onBack={handleBack} />
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* ✅ Form */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: { sm: '60%' },
|
||||||
|
minHeight: { xs: '100vh', sm: '130vh', md: '90vh' },
|
||||||
|
position: 'relative',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
paddingTop: { xs: 2, sm: 4 },
|
||||||
|
paddingLeft: { xs: 2, sm: 4 },
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: 686,
|
||||||
|
pr: { xs: 3, sm: 2, md: 1 },
|
||||||
|
pt: { xs: 2, sm: 4, md: 1 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack spacing={2} alignItems="flex-start">
|
||||||
|
|
||||||
|
|
||||||
|
{/* إظهار المكون الحالي فقط */}
|
||||||
|
<CurrentComponent
|
||||||
|
emailOrPhone={emailOrPhone}
|
||||||
|
setEmailOrPhone={setEmailOrPhone}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* ✅ مؤشر الشرائح السفلي */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: { xs: 'absolute', sm: 'absolute' },
|
||||||
|
bottom: { xs: '5%', sm: '-1%', md: '2%' },
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translateX(-50%)',
|
||||||
|
display: 'flex',
|
||||||
|
gap: 1,
|
||||||
|
width: '80%',
|
||||||
|
maxWidth: 600,
|
||||||
|
justifyContent: 'center',
|
||||||
|
height: {
|
||||||
|
xs: 3,
|
||||||
|
sm: 5,
|
||||||
|
md: 6,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{slides.map((_, index) => (
|
||||||
|
<Box
|
||||||
|
key={index}
|
||||||
|
sx={{
|
||||||
|
width: '100vh',
|
||||||
|
height: 5,
|
||||||
|
bgcolor: index === currentSlide ? theme.palette.primary.main : 'rgba(0, 0, 0, 0.2)',
|
||||||
|
borderRadius: 2,
|
||||||
|
cursor: 'pointer',
|
||||||
|
transition: 'background-color 0.3s',
|
||||||
|
}}
|
||||||
|
// onClick={() => setCurrentSlide(index)} // يمكنك تفعيلها لاحقًا
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ForgetForm;
|
||||||
217
src/components/Authentication/ForgetPassword/NewPassword.js
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
// EmailInputSection.js
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Box, Button, TextField, Typography } from '@mui/material';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import { IconButton, InputAdornment } from '@mui/material';
|
||||||
|
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
|
||||||
|
import { VisibilityOutlined } from '@mui/icons-material';
|
||||||
|
|
||||||
|
const EmailInputSection = ({ emailOrPhone, setEmailOrPhone }) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const handleTogglePassword = () => {
|
||||||
|
setShowPassword((prev) => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
||||||
|
const [currentSlide, setCurrentSlide] = useState(0);
|
||||||
|
const slides = [0, 1, 2, 3];
|
||||||
|
|
||||||
|
const handleSend = () => {
|
||||||
|
// عملية الإرسال
|
||||||
|
};
|
||||||
|
const handleToggleConfirmPassword = () => {
|
||||||
|
setShowConfirmPassword((prev) => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNext = () => {
|
||||||
|
if (currentSlide < slides.length - 1) {
|
||||||
|
setCurrentSlide(prev => prev + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
if (currentSlide > 0) {
|
||||||
|
setCurrentSlide(prev => prev - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box>
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src="/image.png"
|
||||||
|
alt="logo"
|
||||||
|
sx={{
|
||||||
|
width: { xs: '5vh', sm: '7vh' },
|
||||||
|
maxWidth: { xs: '40px', sm: '80px' },
|
||||||
|
height: 'auto',
|
||||||
|
objectFit: 'contain'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
fontWeight={700}
|
||||||
|
sx={{
|
||||||
|
fontSize: {
|
||||||
|
xs: '1.8rem',
|
||||||
|
sm: '2rem',
|
||||||
|
md: '2.2rem'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Create a New Password
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography variant="body1" color="text.secondary">
|
||||||
|
Enter your email to reset it and regai access to your account.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Password Input */}
|
||||||
|
<Box sx={{ width: '100%', display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="black"
|
||||||
|
sx={{
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: '16px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Password
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
type={showPassword ? 'text' : 'password'}
|
||||||
|
placeholder="Enter your password"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
autoComplete="new-password"
|
||||||
|
sx={{
|
||||||
|
'& input': {
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '15px'
|
||||||
|
},
|
||||||
|
'& input::placeholder': {
|
||||||
|
color: '#969BA7'
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: '10px',
|
||||||
|
transition: '0.3s',
|
||||||
|
'&.Mui-focused fieldset': { // أضف هذا الجزء لتغيير لون الحدود عند التركيز
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
boxShadow: '0 0 0 2px rgba(255, 145, 77, 0.2)' // ظل برتقالي خفيف
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& input::-ms-reveal, & input::-ms-clear': {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton onClick={handleTogglePassword} edge="end">
|
||||||
|
{showPassword ? <VisibilityOffOutlinedIcon /> : <VisibilityOutlined />}
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
|
{/* Confirm Password Input */}
|
||||||
|
<Box sx={{ width: '100%', display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="black"
|
||||||
|
sx={{
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: '16px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Confirm Password
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
type={showConfirmPassword ? 'text' : 'password'}
|
||||||
|
placeholder="Confirm your password"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
autoComplete="new-password"
|
||||||
|
sx={{
|
||||||
|
'& input': {
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '15px'
|
||||||
|
},
|
||||||
|
'& input::placeholder': {
|
||||||
|
color: '#969BA7'
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: '10px',
|
||||||
|
transition: '0.3s',
|
||||||
|
'&.Mui-focused fieldset': { // أضف هذا الجزء لتغيير لون الحدود عند التركيز
|
||||||
|
borderColor: '#FF914D',
|
||||||
|
boxShadow: '0 0 0 2px rgba(255, 145, 77, 0.2)' // ظل برتقالي خفيف
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root.Mui-focused': {
|
||||||
|
borderColor: '#3f51b5',
|
||||||
|
boxShadow: '0 0 0 2px rgba(63,81,181,0.1)'
|
||||||
|
},
|
||||||
|
'& input::-ms-reveal, & input::-ms-clear': {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton onClick={handleToggleConfirmPassword} edge="end">
|
||||||
|
{showConfirmPassword ? <VisibilityOffOutlinedIcon /> : <VisibilityOutlined />}
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* send */}
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
onClick={handleSend}
|
||||||
|
sx={{
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
borderRadius: '30px',
|
||||||
|
textTransform: 'none',
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: '16px',
|
||||||
|
height: '48px',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.primary.hover ,
|
||||||
|
transition: 'all 0.4s ease'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Send
|
||||||
|
</Button>
|
||||||
|
<Typography
|
||||||
|
textAlign="center"
|
||||||
|
fontWeight={500}
|
||||||
|
sx={{
|
||||||
|
fontSize: '16px',
|
||||||
|
display: 'block',
|
||||||
|
width: '100%',
|
||||||
|
mx: 'auto',
|
||||||
|
color: '#969BA7'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
By log in, I agree to the
|
||||||
|
<a href="#" style={{ color: '#007bff', textDecoration: 'none' }}>Terms of Service</a> and
|
||||||
|
<a href="#" style={{ color: '#007bff', textDecoration: 'none' }}>Privacy Policy</a>
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EmailInputSection;
|
||||||
183
src/components/Authentication/ForgetPassword/OtpVerification.js
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
import React, { useState, useRef } from 'react';
|
||||||
|
import { Box, TextField, Typography, Button, Stack ,useTheme} from '@mui/material';
|
||||||
|
|
||||||
|
const OtpVerification = () => {
|
||||||
|
const [emailOrPhone, setEmailOrPhone] = useState('');
|
||||||
|
const [currentSlide, setCurrentSlide] = useState(0);
|
||||||
|
const slides = [0, 1, 2, 3];
|
||||||
|
|
||||||
|
const [otp, setOtp] = useState(Array(7).fill(''));
|
||||||
|
const inputRefs = useRef(Array(7).fill().map(() => React.createRef()));
|
||||||
|
|
||||||
|
const handleSend = () => {
|
||||||
|
const otpCode = otp.join('');
|
||||||
|
console.log('Submitted OTP:', otpCode);
|
||||||
|
// عملية التحقق من الكود
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOtpChange = (e, index) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
if (!/^[0-9]?$/.test(value)) return;
|
||||||
|
|
||||||
|
const newOtp = [...otp];
|
||||||
|
newOtp[index] = value;
|
||||||
|
setOtp(newOtp);
|
||||||
|
|
||||||
|
if (value && index < 6) {
|
||||||
|
inputRefs.current[index + 1].current.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (e, index) => {
|
||||||
|
if (e.key === 'Backspace' && !otp[index] && index > 0) {
|
||||||
|
inputRefs.current[index - 1].current.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNext = () => {
|
||||||
|
if (currentSlide < slides.length - 1) {
|
||||||
|
setCurrentSlide(prev => prev + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
if (currentSlide > 0) {
|
||||||
|
setCurrentSlide(prev => prev - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box>
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src="/image.png"
|
||||||
|
alt="logo"
|
||||||
|
sx={{
|
||||||
|
width: { xs: '5vh', sm: '7vh' },
|
||||||
|
maxWidth: { xs: '40px', sm: '80px' },
|
||||||
|
height: 'auto',
|
||||||
|
objectFit: 'contain'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
fontWeight={700}
|
||||||
|
sx={{
|
||||||
|
fontSize: {
|
||||||
|
xs: '1.8rem',
|
||||||
|
sm: '2rem',
|
||||||
|
md: '2.2rem'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Enter OTP Verification
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography variant="body1" color="text.secondary">
|
||||||
|
Kindly enter the OTP code sent to your registered email/phone for account verification.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Box sx={{ width: '100%', display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
|
|
||||||
|
<Stack
|
||||||
|
direction="row"
|
||||||
|
spacing={{ xs: 0, sm: 1, md: 1.5 }}
|
||||||
|
justifyContent={{ xs: 'center', sm: 'center', md: 'flex-start' }}
|
||||||
|
flexWrap="wrap"
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
px: { xs: 0, sm: '0.5rem', md: '1.5rem' },
|
||||||
|
gap: { xs: '1.5rem', sm: '1.5rem', md: '1rem' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{otp.map((digit, index) => (
|
||||||
|
<TextField
|
||||||
|
key={index}
|
||||||
|
inputRef={inputRefs.current[index]}
|
||||||
|
value={digit}
|
||||||
|
onChange={(e) => handleOtpChange(e, index)}
|
||||||
|
onKeyDown={(e) => handleKeyDown(e, index)}
|
||||||
|
inputProps={{
|
||||||
|
maxLength: 1,
|
||||||
|
style: {
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: '20px',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
width: { xs: '3rem', sm: '3.25rem', md: '4rem' },
|
||||||
|
height: { xs: '3rem', sm: '3.25rem', md: '4rem' },
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: '0.5rem',
|
||||||
|
height: '100%', // تأكيد تطابق الطول
|
||||||
|
'& fieldset': {
|
||||||
|
borderColor: '#ccc',
|
||||||
|
},
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
},
|
||||||
|
'&.Mui-focused fieldset': {
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'& .MuiInputBase-input': {
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: '20px',
|
||||||
|
padding: 0,
|
||||||
|
height: '100%',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
onClick={handleSend}
|
||||||
|
sx={{
|
||||||
|
color:'white',
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
borderRadius: '30px',
|
||||||
|
textTransform: 'none',
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: '16px',
|
||||||
|
width: '95%',
|
||||||
|
height: '48px',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.primary.hover ,
|
||||||
|
transition: 'all 0.4s ease'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Send
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
textAlign="center"
|
||||||
|
fontWeight={500}
|
||||||
|
sx={{
|
||||||
|
fontSize: '16px',
|
||||||
|
display: 'block',
|
||||||
|
width: '100%',
|
||||||
|
mx: 'auto',
|
||||||
|
color: '#969BA7'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
By log in, I agree to the
|
||||||
|
<a href="#" style={{ color: '#007bff', textDecoration: 'none' }}>Terms of Service</a> and
|
||||||
|
<a href="#" style={{ color: '#007bff', textDecoration: 'none' }}>Privacy Policy</a>
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OtpVerification;
|
||||||
187
src/components/Authentication/ForgetPassword/Side.js
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Box, Typography, Stack, Button ,useTheme } from '@mui/material';
|
||||||
|
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
||||||
|
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
|
||||||
|
|
||||||
|
const steps = [
|
||||||
|
{
|
||||||
|
title: 'Forget Password',
|
||||||
|
description: 'Provide an email to change your password',
|
||||||
|
icon: '/images/icons/key.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Verify your email',
|
||||||
|
description: 'Enter your otp verification',
|
||||||
|
icon: '/images/icons/email.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Create a new password',
|
||||||
|
description: 'Create your a new password',
|
||||||
|
icon: '/images/icons/pen.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Welcome to KitchPlus app',
|
||||||
|
description: 'Get up and running in 3 minutes',
|
||||||
|
icon: '/images/icons/rocket.png',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const Side = ({ currentStepIndex, onNext, onBack }) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
height: { xs: '100vh', sm: '130vh', md: '87.5vh' },
|
||||||
|
backgroundColor: '#FAFAFA',
|
||||||
|
px: { xs: 2, sm: 4 },
|
||||||
|
py: 5,
|
||||||
|
display: { xs: 'none', sm: 'block' },
|
||||||
|
position: 'relative',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h6" fontWeight={700} mb={2}>
|
||||||
|
Step for change your password
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary" mb={4}>
|
||||||
|
Instructions for secure password modification. Follow simple steps for password change.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Stack spacing={6} position="relative" sx={{ ml: 3 }}>
|
||||||
|
{steps.map((step, index) => (
|
||||||
|
<Box key={index} display="flex" alignItems="flex-start" gap={2} position="relative">
|
||||||
|
{index !== steps.length - 1 && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
left: '3.8vh',
|
||||||
|
top: '6vh',
|
||||||
|
width: '2px',
|
||||||
|
height: 'calc(100% + 24px)',
|
||||||
|
backgroundColor: '#e0e0e0',
|
||||||
|
zIndex: 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'relative',
|
||||||
|
width: 50,
|
||||||
|
height: 53,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
width: 60,
|
||||||
|
height: 63,
|
||||||
|
borderRadius: '50%',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
zIndex: 0,
|
||||||
|
backgroundImage:
|
||||||
|
index === currentStepIndex
|
||||||
|
? 'linear-gradient(0deg, #FF914D, #F3F3F3 )'
|
||||||
|
: 'none',
|
||||||
|
backgroundColor: index === currentStepIndex ? 'transparent' : '#F3F3F3',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: 50,
|
||||||
|
height: 53,
|
||||||
|
backgroundColor: '#FFFFFF',
|
||||||
|
borderRadius: '50%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
zIndex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={step.icon}
|
||||||
|
alt={step.title}
|
||||||
|
style={{ width: 24, height: 24, objectFit: 'contain' }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
<Typography variant="subtitle1" sx={{ fontSize: '16px', fontWeight: 600 }}>
|
||||||
|
{step.title}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" sx={{ color: '#A0A0A0', fontSize: '12px', fontWeight: 500 }}>
|
||||||
|
{step.description}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
{/* ... (بقية محتوى الـ Side كما هو بدون تغيير) ... */}
|
||||||
|
|
||||||
|
{/* أزرار التنقل */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 2,
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translateX(-50%)',
|
||||||
|
width: '90%',
|
||||||
|
maxWidth: 600,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
px: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
||||||
|
{/* Back */}
|
||||||
|
<Button
|
||||||
|
variant="text"
|
||||||
|
startIcon={<ArrowBackIosIcon sx={{ fontSize: '16px' }} />}
|
||||||
|
onClick={onBack}
|
||||||
|
disabled={currentStepIndex === 0}
|
||||||
|
sx={{
|
||||||
|
color: currentStepIndex === 0 ? '#C2C2C2' : '#6B7283',
|
||||||
|
minWidth: '100px',
|
||||||
|
fontWeight: 400,
|
||||||
|
fontSize: '16px',
|
||||||
|
textTransform: 'none',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
color: theme.palette.primary.main
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Back
|
||||||
|
</Button>
|
||||||
|
{/* Next */}
|
||||||
|
<Button
|
||||||
|
variant="text"
|
||||||
|
endIcon={<ArrowForwardIosIcon sx={{ fontSize: '16px' }} />}
|
||||||
|
onClick={onNext}
|
||||||
|
disabled={currentStepIndex === steps.length - 1}
|
||||||
|
sx={{
|
||||||
|
color: currentStepIndex === steps.length - 1 ? '#C2C2C2' : '#6B7283',
|
||||||
|
minWidth: '100px',
|
||||||
|
fontWeight: 400,
|
||||||
|
fontSize: '16px',
|
||||||
|
textTransform: 'none',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
transition: 'all 0.4s ease'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Side;
|
||||||
349
src/components/Authentication/SignUp_In/LoginForm.js
Normal file
@@ -0,0 +1,349 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { TextField, Button, Typography, Stack, Box, IconButton, InputAdornment } from '@mui/material';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
|
||||||
|
import { VisibilityOutlined } from '@mui/icons-material';
|
||||||
|
import SidePanel from './SidePanel'; // استدعاء SidePanel من نفس المجلد أو حسب المسار المناسب
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
|
||||||
|
const LoginForm = () => {
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const theme = useTheme();
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
|
||||||
|
const handleTogglePassword = () => {
|
||||||
|
setShowPassword((prev) => !prev);
|
||||||
|
};
|
||||||
|
const handleLogin = () => {
|
||||||
|
// بعد تنفيذ عملية تسجيل الدخول بنجاح، يتم التوجيه
|
||||||
|
navigate('/dashboard');
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
|
||||||
|
|
||||||
|
<Box
|
||||||
|
bgcolor={"background.default"}
|
||||||
|
color={"text.primary"}
|
||||||
|
display="flex"
|
||||||
|
sx={{
|
||||||
|
width: '100vw',
|
||||||
|
height: '100vh',
|
||||||
|
overflow: 'auto',
|
||||||
|
scrollbarWidth: 'none',
|
||||||
|
'&::-webkit-scrollbar': {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* SidePanel ثابت */}
|
||||||
|
<SidePanel />
|
||||||
|
|
||||||
|
{/* Login Content */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginLeft: { xs: 0, sm: '50%' },
|
||||||
|
width: { xs: '100%', sm: '50%' ,md:'70%'},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
flex={1}
|
||||||
|
paddingTop={4}
|
||||||
|
paddingBottom={4}
|
||||||
|
paddingLeft={2}
|
||||||
|
paddingRight={2}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: '#FFFFFF',
|
||||||
|
minHeight: '10vh',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
position: 'sticky',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: {
|
||||||
|
xs: '120%',
|
||||||
|
sm: '100%',
|
||||||
|
md: '150%',
|
||||||
|
lg: '150%'
|
||||||
|
},
|
||||||
|
maxWidth: '600px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack spacing={2}>
|
||||||
|
|
||||||
|
{/* Logo */}
|
||||||
|
<Box>
|
||||||
|
<img
|
||||||
|
src="/image.png"
|
||||||
|
alt="logo"
|
||||||
|
style={{
|
||||||
|
width: '4vw',
|
||||||
|
maxWidth: '80px',
|
||||||
|
height: 'auto',
|
||||||
|
objectFit: 'contain'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
fontWeight={700}
|
||||||
|
sx={{
|
||||||
|
fontSize: {
|
||||||
|
xs: '1.8rem',
|
||||||
|
sm: '2rem',
|
||||||
|
md: '2.2rem'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="text.secondary"
|
||||||
|
fontWeight={500}
|
||||||
|
sx={{ pb: 1 }}
|
||||||
|
>
|
||||||
|
Enter your username and password to access your account securely. Welcome back to our service!
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Email Input */}
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
|
<Typography variant="body2" color="black" sx={{ fontWeight: '500', fontSize: '16px' }}>
|
||||||
|
Email
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
placeholder="Enter your email"
|
||||||
|
type="email"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
sx={{
|
||||||
|
'& input': { fontWeight: 500, fontSize: '15px' },
|
||||||
|
'& input::placeholder': { color: '#969BA7' },
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: '10px',
|
||||||
|
transition: '0.3s',
|
||||||
|
'&.Mui-focused fieldset': { // أضف هذا الجزء لتغيير لون الحدود عند التركيز
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
boxShadow: '0 0 0 2px rgba(255, 145, 77, 0.2)' // ظل برتقالي خفيف
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root.Mui-focused': {
|
||||||
|
borderColor: '#3f51b5',
|
||||||
|
boxShadow: '0 0 0 2px rgba(63,81,181,0.1)'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Password Input */}
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
|
<Typography variant="body2" color="black" sx={{ fontWeight: '500', fontSize: '16px' }}>
|
||||||
|
Password
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
type={showPassword ? 'text' : 'password'}
|
||||||
|
placeholder="Enter your password"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
autoComplete="new-password"
|
||||||
|
sx={{
|
||||||
|
'& input': { fontWeight: 500, fontSize: '15px' },
|
||||||
|
'& input::placeholder': { color: '#969BA7' },
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: '10px',
|
||||||
|
transition: '0.3s',
|
||||||
|
'&.Mui-focused fieldset': { // أضف هذا الجزء لتغيير لون الحدود عند التركيز
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
boxShadow: '0 0 0 2px rgba(255, 145, 77, 0.2)' // ظل برتقالي خفيف
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root.Mui-focused': {
|
||||||
|
borderColor: '#3f51b5',
|
||||||
|
boxShadow: '0 0 0 2px rgba(63,81,181,0.1)'
|
||||||
|
},
|
||||||
|
'& input::-ms-reveal, & input::-ms-clear': {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton onClick={handleTogglePassword} edge="end">
|
||||||
|
{showPassword ? <VisibilityOffOutlinedIcon /> : <VisibilityOutlined />}
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Login Button */}
|
||||||
|
<Box sx={{ pt: 2 }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
onClick={handleLogin}
|
||||||
|
sx={{
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: { xs: '14px', sm: '16px' },
|
||||||
|
height: { xs: '45px', sm: '52px' },
|
||||||
|
borderRadius: '50px',
|
||||||
|
textTransform: 'none',
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.primary.hover
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Log in
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Divider */}
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, py: 2 }}>
|
||||||
|
<Box sx={{ flex: 1, height: '1px', backgroundColor: '#E0E0E0' }} />
|
||||||
|
<Typography variant="body1" sx={{ fontWeight: 500, fontSize: '16px', color: 'black' }}>
|
||||||
|
Or
|
||||||
|
</Typography>
|
||||||
|
<Box sx={{ flex: 1, height: '1px', backgroundColor: '#E0E0E0' }} />
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Google Button */}
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
sx={{
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '16px',
|
||||||
|
borderRadius: '50px',
|
||||||
|
height: '50px',
|
||||||
|
textTransform: 'none',
|
||||||
|
gap: 1,
|
||||||
|
borderColor: '#E6E6E6',
|
||||||
|
color: 'black',
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: 'black',
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
<img
|
||||||
|
src="https://upload.wikimedia.org/wikipedia/commons/c/c1/Google_%22G%22_logo.svg"
|
||||||
|
alt="Google"
|
||||||
|
style={{ width: 25, height: 25 }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
Login with Google
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{/* Facebook Button */}
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
sx={{
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '16px',
|
||||||
|
borderRadius: '50px',
|
||||||
|
height: '50px',
|
||||||
|
textTransform: 'none',
|
||||||
|
gap: 1,
|
||||||
|
borderColor: '#E6E6E6',
|
||||||
|
color: 'black',
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: 'black',
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
<img
|
||||||
|
src="https://upload.wikimedia.org/wikipedia/commons/0/05/Facebook_Logo_%282019%29.png"
|
||||||
|
alt="Facebook"
|
||||||
|
style={{ width: 25, height: 25 }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
Login with Facebook
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
|
||||||
|
{/* Register Link */}
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
fontSize: '16px',
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#969BA7',
|
||||||
|
pt: 3
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Don’t have an account?{' '}
|
||||||
|
<Link
|
||||||
|
to="/register"
|
||||||
|
style={{
|
||||||
|
color: '#2261FF',
|
||||||
|
textDecoration: 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Register
|
||||||
|
</Link>
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* ForgetPassword Link */}
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
fontSize: '14px',
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#969BA7',
|
||||||
|
pt: 3
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Did you forget the password?{' '}
|
||||||
|
<Link
|
||||||
|
to="/forget"
|
||||||
|
style={{
|
||||||
|
color: '#2261FF',
|
||||||
|
textDecoration: 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Forget Password
|
||||||
|
</Link>
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Terms */}
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
sx={{
|
||||||
|
fontSize: '14px',
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#969BA7',
|
||||||
|
pt: 5
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
By logging in, I agree to the{' '}
|
||||||
|
<a href="#" style={{ color: '#2261FF', textDecoration: 'none' }}>
|
||||||
|
Terms of Service
|
||||||
|
</a>{' '}
|
||||||
|
and{' '}
|
||||||
|
<a href="#" style={{ color: '#2261FF', textDecoration: 'none' }}>
|
||||||
|
Privacy Policy
|
||||||
|
</a>.
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoginForm;
|
||||||
409
src/components/Authentication/SignUp_In/RegisterForm.js
Normal file
@@ -0,0 +1,409 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { TextField, Button, Typography, Stack, Box, IconButton, InputAdornment } from '@mui/material';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
|
||||||
|
import { VisibilityOutlined } from '@mui/icons-material';
|
||||||
|
import SidePanel from './SidePanel';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
const Register = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
||||||
|
|
||||||
|
const handleTogglePassword = () => {
|
||||||
|
setShowPassword((prev) => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleToggleConfirmPassword = () => {
|
||||||
|
setShowConfirmPassword((prev) => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box bgcolor={"background.default"} color={"text.primary"} display="flex" sx={{
|
||||||
|
width: '100vw',
|
||||||
|
height: '100vh',
|
||||||
|
overflow: 'auto',
|
||||||
|
scrollbarWidth: 'none',
|
||||||
|
'&::-webkit-scrollbar': {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
}}>
|
||||||
|
{/* SidePanel ثابت */}
|
||||||
|
|
||||||
|
<SidePanel />
|
||||||
|
|
||||||
|
{/* Login Content */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginLeft: { xs: 0, sm: '50%' },
|
||||||
|
width: { xs: '100%', sm: '50%' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
flex={1}
|
||||||
|
paddingTop={4}
|
||||||
|
paddingBottom={4}
|
||||||
|
paddingLeft={2}
|
||||||
|
paddingRight={2}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: '#FFFFFF',
|
||||||
|
minHeight: '10vh',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
position: 'sticky',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: {
|
||||||
|
xs: '120%',
|
||||||
|
sm: '100%',
|
||||||
|
md: '120%',
|
||||||
|
lg: '120%'
|
||||||
|
},
|
||||||
|
maxWidth: '600px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack spacing={2}>
|
||||||
|
|
||||||
|
{/* Logo */}
|
||||||
|
<Box>
|
||||||
|
<img
|
||||||
|
src="/image.png"
|
||||||
|
alt="logo"
|
||||||
|
style={{
|
||||||
|
width: '4vw',
|
||||||
|
maxWidth: '80px',
|
||||||
|
height: 'auto',
|
||||||
|
objectFit: 'contain'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
fontWeight={700}
|
||||||
|
sx={{
|
||||||
|
fontSize: {
|
||||||
|
xs: '1.8rem',
|
||||||
|
sm: '2rem',
|
||||||
|
md: '2.2rem'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Register
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="text.secondary"
|
||||||
|
fontWeight={500}
|
||||||
|
sx={{ pb: 1 }}
|
||||||
|
>
|
||||||
|
Please fill out the registration form with accurate information to
|
||||||
|
create your account successfully.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Email Input */}
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="black"
|
||||||
|
sx={{
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: '16px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Email
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
placeholder="Enter your email"
|
||||||
|
type="email"
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
sx={{
|
||||||
|
'& input': {
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '15px'
|
||||||
|
},
|
||||||
|
'& input::placeholder': {
|
||||||
|
color: '#969BA7'
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: '10px',
|
||||||
|
transition: '0.3s',
|
||||||
|
'&.Mui-focused fieldset': { // أضف هذا الجزء لتغيير لون الحدود عند التركيز
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
boxShadow: '0 0 0 2px rgba(255, 145, 77, 0.2)' // ظل برتقالي خفيف
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root.Mui-focused': {
|
||||||
|
borderColor: '#3f51b5',
|
||||||
|
boxShadow: '0 0 0 2px rgba(63,81,181,0.1)'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Password Input */}
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="black"
|
||||||
|
sx={{
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: '16px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Password
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
type={showPassword ? 'text' : 'password'}
|
||||||
|
placeholder="Enter your password"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
autoComplete="new-password"
|
||||||
|
sx={{
|
||||||
|
'& input': {
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '15px'
|
||||||
|
},
|
||||||
|
'& input::placeholder': {
|
||||||
|
color: '#969BA7'
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: '10px',
|
||||||
|
transition: '0.3s',
|
||||||
|
'&.Mui-focused fieldset': { // أضف هذا الجزء لتغيير لون الحدود عند التركيز
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
boxShadow: '0 0 0 2px rgba(255, 145, 77, 0.2)' // ظل برتقالي خفيف
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root.Mui-focused': {
|
||||||
|
borderColor: '#3f51b5',
|
||||||
|
boxShadow: '0 0 0 2px rgba(63,81,181,0.1)'
|
||||||
|
},
|
||||||
|
'& input::-ms-reveal, & input::-ms-clear': {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton onClick={handleTogglePassword} edge="end">
|
||||||
|
{showPassword ? <VisibilityOffOutlinedIcon /> : <VisibilityOutlined />}
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Confirm Password Input */}
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="black"
|
||||||
|
sx={{
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: '16px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Confirm Password
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
type={showConfirmPassword ? 'text' : 'password'}
|
||||||
|
placeholder="Confirm your password"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
autoComplete="new-password"
|
||||||
|
sx={{
|
||||||
|
'& input': {
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '15px'
|
||||||
|
},
|
||||||
|
'& input::placeholder': {
|
||||||
|
color: '#969BA7'
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: '10px',
|
||||||
|
transition: '0.3s',
|
||||||
|
'&.Mui-focused fieldset': { // أضف هذا الجزء لتغيير لون الحدود عند التركيز
|
||||||
|
borderColor: '#FF914D',
|
||||||
|
boxShadow: '0 0 0 2px rgba(255, 145, 77, 0.2)' // ظل برتقالي خفيف
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiOutlinedInput-root.Mui-focused': {
|
||||||
|
borderColor: '#3f51b5',
|
||||||
|
boxShadow: '0 0 0 2px rgba(63,81,181,0.1)'
|
||||||
|
},
|
||||||
|
'& input::-ms-reveal, & input::-ms-clear': {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton onClick={handleToggleConfirmPassword} edge="end">
|
||||||
|
{showConfirmPassword ? <VisibilityOffOutlinedIcon /> : <VisibilityOutlined />}
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Login Button */}
|
||||||
|
<Box sx={{ pt: 2 }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
sx={{
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: {
|
||||||
|
xs: '14px',
|
||||||
|
sm: '16px'
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
xs: '45px',
|
||||||
|
sm: '52px'
|
||||||
|
},
|
||||||
|
borderRadius: '50px',
|
||||||
|
textTransform: 'none',
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.primary.hover
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Continue
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Divider */}
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, py: 2 }}>
|
||||||
|
<Box sx={{ flex: 1, height: '1px', backgroundColor: '#E0E0E0' }} />
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
sx={{
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '16px',
|
||||||
|
color: 'black'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Or
|
||||||
|
</Typography>
|
||||||
|
<Box sx={{ flex: 1, height: '1px', backgroundColor: '#E0E0E0' }} />
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Google Button */}
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
sx={{
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '16px',
|
||||||
|
borderRadius: '50px',
|
||||||
|
height: '50px',
|
||||||
|
textTransform: 'none',
|
||||||
|
gap: 1,
|
||||||
|
borderColor: '#E6E6E6',
|
||||||
|
color: 'black',
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: 'black',
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
<img
|
||||||
|
src="https://upload.wikimedia.org/wikipedia/commons/c/c1/Google_%22G%22_logo.svg"
|
||||||
|
alt="Google"
|
||||||
|
style={{ width: 25, height: 25 }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
Login with Google
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{/* Facebook Button */}
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
sx={{
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '16px',
|
||||||
|
borderRadius: '50px',
|
||||||
|
height: '50px',
|
||||||
|
textTransform: 'none',
|
||||||
|
gap: 1,
|
||||||
|
borderColor: '#E6E6E6',
|
||||||
|
color: 'black',
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: 'black',
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
<img
|
||||||
|
src="https://upload.wikimedia.org/wikipedia/commons/0/05/Facebook_Logo_%282019%29.png"
|
||||||
|
alt="Facebook"
|
||||||
|
style={{ width: 25, height: 25 }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
Login with Facebook
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{/* login Link */}
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
fontSize: '16px',
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#969BA7',
|
||||||
|
pt: 3
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Already have an account?{' '}
|
||||||
|
<Link
|
||||||
|
to="/login"
|
||||||
|
style={{
|
||||||
|
color: '#2261FF',
|
||||||
|
textDecoration: 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</Link>
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Terms */}
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
sx={{
|
||||||
|
fontSize: '14px',
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#969BA7',
|
||||||
|
pt: 5
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
By log in, I agree to the and {' '}
|
||||||
|
<a href="#" style={{ color: '#2261FF', textDecoration: 'none' }}>
|
||||||
|
Terms of Service
|
||||||
|
</a>{' '}
|
||||||
|
and{' '}
|
||||||
|
<a href="#" style={{ color: '#2261FF', textDecoration: 'none' }}>
|
||||||
|
Privacy Policy
|
||||||
|
</a>.
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Register;
|
||||||
194
src/components/Authentication/SignUp_In/SidePanel.js
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Typography,
|
||||||
|
Stack,
|
||||||
|
Box
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; // استيراد أيقونة السهم
|
||||||
|
|
||||||
|
const SidePanel = ({ setMode, mode }) => {
|
||||||
|
const [currentSlide, setCurrentSlide] = useState(0);
|
||||||
|
|
||||||
|
const slides = [
|
||||||
|
{
|
||||||
|
image: '/images/waitress3.png',
|
||||||
|
title: "Welcome to our cutting-edge postal application,",
|
||||||
|
description: "Welcome to our cutting-edge postal application, where sending and receiving mail has never been more convenient and efficient."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/images/waitress3.png',
|
||||||
|
title: "Second Slide Title",
|
||||||
|
description: "Welcome to our cutting-edge postal application, where sending and receiving mail has never been more convenient and efficient."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/images/waitress3.png',
|
||||||
|
title: "Third Slide Title",
|
||||||
|
description: "Welcome to our cutting-edge postal application, where sending and receiving mail has never been more convenient and efficient."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: '/images/waitress3.png',
|
||||||
|
title: "Fourth Slide Title",
|
||||||
|
description: "Welcome to our cutting-edge postal application, where sending and receiving mail has never been more convenient and efficient."
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
setCurrentSlide((prev) => (prev + 1) % slides.length);
|
||||||
|
}, 5000);
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, [slides.length]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: { xs: 'none', sm: 'block' },
|
||||||
|
width: { sm: '50%' },
|
||||||
|
position: 'fixed',
|
||||||
|
height: '100vh',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
zIndex: 10,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
flex={1}
|
||||||
|
padding={2}
|
||||||
|
sx={{
|
||||||
|
display: { xs: "none", sm: "block" },
|
||||||
|
position: 'sticky',
|
||||||
|
height: 'calc(102vh - 40px)', // لضمان ملاءمته للشاشة
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
||||||
|
<Stack spacing={2} sx={{ width: '100%', height: '100%' }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100vh',
|
||||||
|
position: 'relative',
|
||||||
|
overflow: 'hidden',
|
||||||
|
borderRadius: '20px',
|
||||||
|
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* الصورة الحالية */}
|
||||||
|
<img
|
||||||
|
src={slides[currentSlide].image}
|
||||||
|
alt={`Slide ${currentSlide + 1}`}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
objectFit: 'cover',
|
||||||
|
display: 'block'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* مربع النص في الأسفل */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
width: '100%',
|
||||||
|
height: {
|
||||||
|
md: '37vh', // الافتراضي للشاشات الصغيرة
|
||||||
|
// xs: '5vh',
|
||||||
|
sm: '42vh',// عندما تكون الشاشة متوسطة أو أكبر
|
||||||
|
lg: '31vh', // من 1200px إلى أقل من 1536px
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
bgcolor: 'rgba(0, 0, 0, 0.2)',
|
||||||
|
color: 'white',
|
||||||
|
borderBottomLeftRadius: '20px',
|
||||||
|
borderBottomRightRadius: '20px',
|
||||||
|
p: 3,
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
boxShadow: '0px -40px 20px rgba(0, 0, 0, 0.2)',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
size="small"
|
||||||
|
onClick={() => window.open('https://www.google.com', '_blank')}
|
||||||
|
sx={{
|
||||||
|
|
||||||
|
mb: 1,
|
||||||
|
bgcolor: 'rgba(255, 255, 255, 0.24)',
|
||||||
|
color: 'white',
|
||||||
|
textTransform: 'none',
|
||||||
|
borderRadius: '12px', // زاوية منحنية
|
||||||
|
display: 'flex', // لتوزيع الأيقونة والنص بشكل أفقي
|
||||||
|
alignItems: 'center', // لضبط الأيقونة والنص في المنتصف
|
||||||
|
padding: '6px 20px', // يمكن تعديل المسافة حول النص والأيقونة
|
||||||
|
borderRadius: '50px',
|
||||||
|
fontSize: '16px',
|
||||||
|
fontWeight: 500,
|
||||||
|
marginBottom: '20px'
|
||||||
|
}}
|
||||||
|
|
||||||
|
>
|
||||||
|
KITCHPLUS
|
||||||
|
{/* إضافة أيقونة السهم مع تعديل زاوية الدوران */}
|
||||||
|
<ArrowForwardIcon sx={{ ml: 1, transform: 'rotate(-45deg)' }} /> {/* تعديل زاوية السهم */}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
wordBreak: 'break-word',
|
||||||
|
fontSize: '120%',
|
||||||
|
fontWeight: 400,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{slides[currentSlide].description}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* مؤشرات الشرائح */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: '1vh', // جعل المؤشرات تحت النص
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translateX(-50%)',
|
||||||
|
display: 'flex',
|
||||||
|
gap: 1,
|
||||||
|
width: '100%',
|
||||||
|
justifyContent: 'center', // تأكد من أن المؤشرات تأخذ عرض الصورة بالكامل
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{slides.map((_, index) => (
|
||||||
|
<Box
|
||||||
|
key={index}
|
||||||
|
sx={{
|
||||||
|
width: '20%',
|
||||||
|
height: 5,
|
||||||
|
bgcolor: index === currentSlide ? 'white' : 'rgba(255, 255, 255, 0.5)',
|
||||||
|
borderRadius: 2,
|
||||||
|
cursor: 'pointer',
|
||||||
|
transition: 'background-color 0.3s',
|
||||||
|
}}
|
||||||
|
onClick={() => setCurrentSlide(index)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
<Box position="fixed">
|
||||||
|
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SidePanel;
|
||||||
112
src/components/Home/Analytics&Reporting/Analytics.js
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Box, useTheme, useMediaQuery, Skeleton } from '@mui/material';
|
||||||
|
import KitchPlusAppBar from '../AppBar';
|
||||||
|
import Sidebar from '../SideHome';
|
||||||
|
import AnalyticsContect from './AnalyticsContect';
|
||||||
|
|
||||||
|
const drawerWidth = 230;
|
||||||
|
|
||||||
|
const AnalyticsPage = () => {
|
||||||
|
const [timeFrame, setTimeFrame] = useState('month');
|
||||||
|
|
||||||
|
const theme = useTheme();
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
const [hasProducts, setHasProducts] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(!isMobile);
|
||||||
|
|
||||||
|
// محاكاة التحقق من المنتجات
|
||||||
|
useEffect(() => {
|
||||||
|
const checkProducts = async () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
const productsExist = await checkIfProductsExist(); // استبدل بمنطقك
|
||||||
|
setHasProducts(productsExist);
|
||||||
|
setIsLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
checkProducts();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const checkIfProductsExist = async () => {
|
||||||
|
return new Promise((resolve) => setTimeout(() => resolve(true), 1500)); // محاكاة تأخير
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (window.innerWidth >= theme.breakpoints.values.md) {
|
||||||
|
setSidebarOpen(true);
|
||||||
|
} else {
|
||||||
|
setSidebarOpen(false);
|
||||||
|
}
|
||||||
|
}, [theme.breakpoints.values.md]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
if (window.innerWidth >= theme.breakpoints.values.md) {
|
||||||
|
setSidebarOpen(true);
|
||||||
|
} else {
|
||||||
|
setSidebarOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, [theme.breakpoints.values.md]);
|
||||||
|
|
||||||
|
const handleDrawerToggle = () => {
|
||||||
|
setSidebarOpen(!sidebarOpen);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
|
||||||
|
|
||||||
|
<Box sx={{ display: 'flex', height: '100vh', backgroundColor: '#F6F6F6', overflow: 'hidden' }}>
|
||||||
|
<Sidebar open={sidebarOpen} onClose={handleDrawerToggle} isMobile={isMobile} drawerWidth={drawerWidth} />
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
width: { xs: '100%', sm: sidebarOpen ? `calc(100% - ${drawerWidth}px)` : '100%' },
|
||||||
|
marginLeft: 0,
|
||||||
|
transition: theme.transitions.create(['width'], {
|
||||||
|
easing: theme.transitions.easing.sharp,
|
||||||
|
duration: theme.transitions.duration.leavingScreen,
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
||||||
|
<KitchPlusAppBar onDrawerToggle={handleDrawerToggle} sidebarOpen={sidebarOpen} isMobile={isMobile} />
|
||||||
|
|
||||||
|
<Box sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
width: sidebarOpen ? 'calc(100% - 20px)' : '100%',
|
||||||
|
pt: { xs: 0.5, sm: 1 },
|
||||||
|
mt: { xs: 1, sm: 0 },
|
||||||
|
overflowY: 'auto',
|
||||||
|
pl: { xs: 0, sm: 1 },
|
||||||
|
pr: { xs: 1, sm: 1 },
|
||||||
|
pb: { xs: 1, sm: 2 },
|
||||||
|
scrollbarWidth: 'none',
|
||||||
|
'&::-webkit-scrollbar': { display: 'none' },
|
||||||
|
transition: theme.transitions.create(['margin'], {
|
||||||
|
easing: theme.transitions.easing.sharp,
|
||||||
|
duration: theme.transitions.duration.leavingScreen,
|
||||||
|
}),
|
||||||
|
}}>
|
||||||
|
{isLoading ? (
|
||||||
|
<>
|
||||||
|
<Skeleton variant="rectangular" height={50} sx={{ mb: 2 }} />
|
||||||
|
<Skeleton variant="rectangular" height={200} sx={{ mb: 2 }} />
|
||||||
|
<Skeleton variant="rectangular" height={300} sx={{ mb: 2 }} />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<AnalyticsContect />
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AnalyticsPage;
|
||||||
227
src/components/Home/Analytics&Reporting/AnalyticsContect.js
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import StatisticsCard from './StatisticsCard';
|
||||||
|
import TopSellingProduct from './TopSellingProduct';
|
||||||
|
import SalesByLocation from './SalesByLocation';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
useTheme,
|
||||||
|
useMediaQuery,
|
||||||
|
Skeleton,
|
||||||
|
Button,
|
||||||
|
Typography,
|
||||||
|
ButtonGroup
|
||||||
|
} from '@mui/material';
|
||||||
|
import CalendarTodayOutlinedIcon from '@mui/icons-material/CalendarTodayOutlined';
|
||||||
|
|
||||||
|
const AnalyticsPage = () => {
|
||||||
|
const [timeFrame, setTimeFrame] = useState('month');
|
||||||
|
const theme = useTheme();
|
||||||
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
const [hasProducts, setHasProducts] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(!isMobile);
|
||||||
|
|
||||||
|
const dailyData = [
|
||||||
|
{ date: '10:00', visitors: 1500, conversions: 300 },
|
||||||
|
{ date: '11:00', visitors: 1800, conversions: 320 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const weeklyData = [
|
||||||
|
{ label: 'Week 1', visitors: 1500, conversions: 200 },
|
||||||
|
{ label: 'Week 2', visitors: 2300, conversions: 400 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const monthlyData = [
|
||||||
|
{ label: 'Jan', visitors: 15000, conversions: 3000 },
|
||||||
|
{ label: 'Feb', visitors: 18000, conversions: 4000 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const yearlyData = [
|
||||||
|
{ label: '2024', visitors: 25000, conversions: 7000 },
|
||||||
|
{ label: '2025', visitors: 38000, conversions: 12000 },
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const getData = () => {
|
||||||
|
switch (timeFrame) {
|
||||||
|
case '24h':
|
||||||
|
return dailyData;
|
||||||
|
case '7d':
|
||||||
|
return weeklyData;
|
||||||
|
case '30d':
|
||||||
|
return monthlyData;
|
||||||
|
case '12m':
|
||||||
|
return yearlyData;
|
||||||
|
case 'all':
|
||||||
|
return [...yearlyData, ...monthlyData, ...weeklyData, ...dailyData];
|
||||||
|
default:
|
||||||
|
return dailyData;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const topSellingProducts = [
|
||||||
|
{ product: 'Apple Watch', sales: 150, amount: 45000, price: 299, status: 'Published' },
|
||||||
|
{ product: 'Samsung Galaxy', sales: 90, amount: 36000, price: 400, status: 'Low Stock' },
|
||||||
|
{ product: 'Sony Headphones', sales: 60, amount: 18000, price: 299, status: 'Draft' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const salesData = [
|
||||||
|
{ country: 'United Kingdom', amount: 17678, change: 12, sales: 340 },
|
||||||
|
{ country: 'Spain', amount: 5500, change: -5, sales: 100 },
|
||||||
|
{ country: 'Germany', amount: 24189, change: -25, sales: 540 },
|
||||||
|
];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const checkProducts = async () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
const productsExist = await new Promise((resolve) =>
|
||||||
|
setTimeout(() => resolve(true), 1500)
|
||||||
|
);
|
||||||
|
setHasProducts(productsExist);
|
||||||
|
setIsLoading(false);
|
||||||
|
};
|
||||||
|
checkProducts();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
setSidebarOpen(window.innerWidth >= theme.breakpoints.values.md);
|
||||||
|
};
|
||||||
|
handleResize();
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, [theme.breakpoints.values.md]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
p={{ xs: 1, sm: 2 }}
|
||||||
|
maxWidth="100%"
|
||||||
|
overflowX="hidden"
|
||||||
|
>
|
||||||
|
{/* Header Buttons */}
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
flexDirection={{ xs: 'column', sm: 'row' }}
|
||||||
|
justifyContent="space-between"
|
||||||
|
alignItems="center"
|
||||||
|
gap={2}
|
||||||
|
mb={3}
|
||||||
|
>
|
||||||
|
<ButtonGroup
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
borderRadius: '8px',
|
||||||
|
boxShadow: 'inset 0 0 0 1px #e0e0e0',
|
||||||
|
'& .MuiButton-root': {
|
||||||
|
textTransform: 'none',
|
||||||
|
fontSize: '13px',
|
||||||
|
padding: '6px 12px',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '8px',
|
||||||
|
color: '#555',
|
||||||
|
'&:hover': { backgroundColor: '#f5f5f5' }
|
||||||
|
},
|
||||||
|
'& .MuiButton-contained': {
|
||||||
|
backgroundColor: 'rgba(255, 117, 34, 0.08)',
|
||||||
|
color: '#ff5722',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{[
|
||||||
|
{ label: 'All Time', value: 'all' },
|
||||||
|
{ label: '12 Months', value: '12m' },
|
||||||
|
{ label: '30 Days', value: '30d' },
|
||||||
|
{ label: '7 Days', value: '7d' },
|
||||||
|
{ label: '24 Hour', value: '24h' },
|
||||||
|
].map(({ label, value }) => (
|
||||||
|
<Button
|
||||||
|
key={value}
|
||||||
|
variant={timeFrame === value ? 'contained' : 'text'}
|
||||||
|
onClick={() => setTimeFrame(value)}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</ButtonGroup>
|
||||||
|
|
||||||
|
<Box display="flex" gap={2} flexWrap="wrap" justifyContent={{ xs: 'space-between', sm: 'flex-end' }} width={{ xs: '100%', sm: 'auto' }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
textTransform: 'none',
|
||||||
|
color: '#667085',
|
||||||
|
backgroundColor: 'white',
|
||||||
|
boxShadow: 'none',
|
||||||
|
borderRadius: '8px',
|
||||||
|
height: '40px',
|
||||||
|
fontSize: '13px',
|
||||||
|
fontWeight: 500,
|
||||||
|
border: '1px solid #e0e0e0',
|
||||||
|
gap: 1,
|
||||||
|
minWidth: '120px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CalendarTodayOutlinedIcon sx={{ fontSize: 16 }} />
|
||||||
|
{!isSmallScreen && 'Select Dates'}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
textTransform: 'none',
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
borderRadius: '8px',
|
||||||
|
height: '40px',
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: '14px',
|
||||||
|
minWidth: '100px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
KPIs Filter
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Data Sections */}
|
||||||
|
<Box display="flex" flexDirection={{ xs: 'column', md: 'row' }} gap={2} mb={3}>
|
||||||
|
<Box flex={2}>
|
||||||
|
<TopSellingProduct data={topSellingProducts} />
|
||||||
|
</Box>
|
||||||
|
<Box flex={1}>
|
||||||
|
<SalesByLocation data={salesData} />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Chart Section */}
|
||||||
|
<Box>
|
||||||
|
{isLoading ? (
|
||||||
|
<>
|
||||||
|
<Skeleton variant="rectangular" height={50} sx={{ mb: 2 }} />
|
||||||
|
<Skeleton variant="rectangular" height={200} sx={{ mb: 2 }} />
|
||||||
|
<Skeleton variant="rectangular" height={300} sx={{ mb: 2 }} />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<StatisticsCard
|
||||||
|
title="Analytics Overview"
|
||||||
|
subtitle="Performance Metrics"
|
||||||
|
data={getData()}
|
||||||
|
dataKeys={[
|
||||||
|
{ key: 'visitors', name: 'Visitors', color: '#4CAF50' },
|
||||||
|
{ key: 'conversions', name: 'Conversions', color: '#9C27B0' },
|
||||||
|
]}
|
||||||
|
xDataKey={timeFrame === '24h' ? 'date' : 'label'}
|
||||||
|
timeFrame={timeFrame}
|
||||||
|
onTimeFrameChange={setTimeFrame}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AnalyticsPage;
|
||||||
124
src/components/Home/Analytics&Reporting/SalesByLocation.js
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Paper,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
ListItemText,
|
||||||
|
ListItemSecondaryAction,
|
||||||
|
Chip,
|
||||||
|
IconButton,
|
||||||
|
useTheme,
|
||||||
|
useMediaQuery
|
||||||
|
} from '@mui/material';
|
||||||
|
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||||
|
const SalesByLocation = ({ data }) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper sx={{
|
||||||
|
p: { xs: 1, sm: 2 },
|
||||||
|
borderRadius: '12px',
|
||||||
|
boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.1)',
|
||||||
|
height: '95%', // إضافة هذه السطر
|
||||||
|
display: 'flex', // إضافة
|
||||||
|
flexDirection: 'column' // إضافة
|
||||||
|
}}>
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
mb: { xs: 0.5, sm: 1 }
|
||||||
|
}}>
|
||||||
|
<Box>
|
||||||
|
<Typography sx={{
|
||||||
|
color: '#1A1C21',
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: { xs: '16px', sm: '18px' },
|
||||||
|
lineHeight: 1.2
|
||||||
|
}}>
|
||||||
|
Sales by Location
|
||||||
|
</Typography>
|
||||||
|
<Typography sx={{
|
||||||
|
color: '#667085',
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: { xs: '12px', sm: '14px' },
|
||||||
|
lineHeight: 1.2
|
||||||
|
}}>
|
||||||
|
Sales performance by location
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<IconButton size={isSmallScreen ? 'small' : 'medium'}>
|
||||||
|
<MoreVertIcon fontSize={isSmallScreen ? 'small' : 'medium'} />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<List dense sx={{
|
||||||
|
flexGrow: 1, // إضافة هذه السطر
|
||||||
|
overflowY: 'auto',
|
||||||
|
'&::-webkit-scrollbar': {
|
||||||
|
display: 'none'
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{data.map((item, i) => (
|
||||||
|
<ListItem key={i} disableGutters sx={{ py: { xs: 0.5, sm: 1 } }}>
|
||||||
|
<ListItemText
|
||||||
|
primary={
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: { xs: '13px', sm: '14px' },
|
||||||
|
fontWeight: 400
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.country}
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
secondary={
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: { xs: '11px', sm: '12px' },
|
||||||
|
color: theme.palette.text.secondary
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.sales} Sales
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
sx={{ my: 0 }}
|
||||||
|
/>
|
||||||
|
<ListItemSecondaryAction sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: { xs: 0.5, sm: 1 }
|
||||||
|
}}>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
fontSize: { xs: '12px', sm: '14px' },
|
||||||
|
fontWeight: isSmallScreen ? 500 : 400
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${item.amount.toLocaleString()}
|
||||||
|
</Typography>
|
||||||
|
<Chip
|
||||||
|
label={`${item.change > 0 ? '+' : ''}${item.change}%`}
|
||||||
|
color={item.change > 0 ? 'success' : item.change < 0 ? 'error' : 'default'}
|
||||||
|
size={isSmallScreen ? 'small' : 'medium'}
|
||||||
|
sx={{
|
||||||
|
fontSize: { xs: '11px', sm: '12px' },
|
||||||
|
height: { xs: '24px', sm: '28px' },
|
||||||
|
'& .MuiChip-label': {
|
||||||
|
px: { xs: 0.5, sm: 1 }
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</ListItemSecondaryAction>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SalesByLocation;
|
||||||
168
src/components/Home/Analytics&Reporting/StatisticsCard.js
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
IconButton,
|
||||||
|
Paper,
|
||||||
|
Typography,
|
||||||
|
useTheme,
|
||||||
|
useMediaQuery
|
||||||
|
} from '@mui/material';
|
||||||
|
import {
|
||||||
|
AreaChart,
|
||||||
|
Area,
|
||||||
|
XAxis,
|
||||||
|
YAxis,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
ResponsiveContainer,
|
||||||
|
CartesianGrid
|
||||||
|
} from 'recharts';
|
||||||
|
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||||
|
|
||||||
|
const formatCurrency = (value) => {
|
||||||
|
if (value >= 1000000) return `$${(value / 1000000).toFixed(1)}M`;
|
||||||
|
if (value >= 1000) return `$${(value / 1000).toFixed(1)}K`;
|
||||||
|
return `$${value}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const StatisticsCard = ({
|
||||||
|
title = "Statistics",
|
||||||
|
subtitle = "Delivery Times",
|
||||||
|
data = [],
|
||||||
|
dataKeys = [
|
||||||
|
{ key: 'revenue', name: 'Revenue', color: '#E46A11' }, // << هنا تغيير اللون
|
||||||
|
{ key: 'sales', name: 'Sales', color: '#0182FC' } // << وهنا أيضاً
|
||||||
|
],
|
||||||
|
xDataKey = 'month',
|
||||||
|
valueFormatter = formatCurrency,
|
||||||
|
timeFrame = 'month',
|
||||||
|
onTimeFrameChange
|
||||||
|
}) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
const isTablet = useMediaQuery(theme.breakpoints.between('sm', 'md'));
|
||||||
|
|
||||||
|
const handleTimeFrameChange = (newTimeFrame) => {
|
||||||
|
if (onTimeFrameChange) onTimeFrameChange(newTimeFrame);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ borderRadius: 2, width: { sm: '100%', md: '167vh' }}}>
|
||||||
|
<Paper sx={{
|
||||||
|
p: { xs: 1.5, sm: 2 },
|
||||||
|
mb: { xs: 2, sm: 2 },
|
||||||
|
boxShadow: '0px 4px 5px rgba(0, 0, 0, 0.1)',
|
||||||
|
borderRadius: 2,
|
||||||
|
position: 'relative'
|
||||||
|
}}>
|
||||||
|
<IconButton
|
||||||
|
aria-label="more-actions"
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: { xs: 4, sm: 8 },
|
||||||
|
right: { xs: 4, sm: 8 },
|
||||||
|
color: '#667085'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MoreVertIcon fontSize={isMobile ? 'small' : 'medium'} />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
{/* Header */}
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
mb: 2,
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
gap: 1
|
||||||
|
}}>
|
||||||
|
<Box>
|
||||||
|
<Typography variant="h6" sx={{ fontSize: { xs: '15px', sm: '18px' }, fontWeight: 500 }}>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
<Typography sx={{ fontSize: { xs: '11px', sm: '14px' }, fontWeight: 500, color: '#667085' }}>
|
||||||
|
{subtitle}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Chart */}
|
||||||
|
<ResponsiveContainer width="100%" height={isMobile ? 250 : isTablet ? 290 : 295}>
|
||||||
|
<AreaChart data={data} margin={{
|
||||||
|
top: isMobile ? -30 : -45,
|
||||||
|
right: isMobile ? 15 : 30,
|
||||||
|
left: isMobile ? 10 : 20,
|
||||||
|
bottom: isMobile ? 10 : 20
|
||||||
|
}}>
|
||||||
|
<defs>
|
||||||
|
{dataKeys.map(({ key, color }) => (
|
||||||
|
<linearGradient key={key} id={`color-${key}`} x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0%" stopColor={color} stopOpacity={0.8} />
|
||||||
|
<stop offset="100%" stopColor={color} stopOpacity={0} />
|
||||||
|
</linearGradient>
|
||||||
|
))}
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<CartesianGrid stroke="#eee" strokeDasharray="0 0" vertical={false} />
|
||||||
|
<XAxis
|
||||||
|
dataKey={xDataKey}
|
||||||
|
axisLine={false}
|
||||||
|
tickLine={false}
|
||||||
|
tickMargin={isMobile ? 8 : 15}
|
||||||
|
tick={{
|
||||||
|
fontSize: isMobile ? 11 : 12,
|
||||||
|
angle: -25, // تدوير النص لتفادي التزاحم
|
||||||
|
textAnchor: 'end'
|
||||||
|
}}
|
||||||
|
interval={0} // عرض كل القيم على محور X
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
tickFormatter={valueFormatter}
|
||||||
|
axisLine={false}
|
||||||
|
tickLine={false}
|
||||||
|
tickMargin={isMobile ? 8 : 15}
|
||||||
|
tick={{ fontSize: isMobile ? 11 : 12 }}
|
||||||
|
/>
|
||||||
|
<Tooltip formatter={valueFormatter} />
|
||||||
|
<Legend
|
||||||
|
verticalAlign="top"
|
||||||
|
height={isMobile ? 30 : 36}
|
||||||
|
iconType="circle"
|
||||||
|
iconSize={isMobile ? 8 : 10}
|
||||||
|
wrapperStyle={{ paddingBottom: isMobile ? '15px' : '20px' }}
|
||||||
|
/>
|
||||||
|
{dataKeys.map(({ key, name, color }) => (
|
||||||
|
<Area
|
||||||
|
key={key}
|
||||||
|
name={name}
|
||||||
|
type="monotone"
|
||||||
|
dataKey={key}
|
||||||
|
stroke={color} // لون الخط
|
||||||
|
strokeWidth={isMobile ? 2 : 3}
|
||||||
|
fill={`url(#color-${key})`} // لون التعبئة بتدرج
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</AreaChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
StatisticsCard.propTypes = {
|
||||||
|
title: PropTypes.string,
|
||||||
|
subtitle: PropTypes.string,
|
||||||
|
data: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
dataKeys: PropTypes.arrayOf(PropTypes.shape({
|
||||||
|
key: PropTypes.string.isRequired,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
color: PropTypes.string.isRequired
|
||||||
|
})),
|
||||||
|
xDataKey: PropTypes.string,
|
||||||
|
valueFormatter: PropTypes.func,
|
||||||
|
timeFrame: PropTypes.oneOf(['day', 'week', 'month', 'year']),
|
||||||
|
onTimeFrameChange: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StatisticsCard;
|
||||||
22
src/components/Home/Analytics&Reporting/TimeFrameSelector.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Button, Stack } from '@mui/material';
|
||||||
|
|
||||||
|
const options = ['All Time', '12 Months', '30 Days', '7 Days', '24 Hour'];
|
||||||
|
|
||||||
|
const TimeFrameSelector = ({ selected, onChange }) => (
|
||||||
|
<Stack direction="row" spacing={1} sx={{ flexWrap: 'wrap', mb: 2 }}>
|
||||||
|
{options.map(option => (
|
||||||
|
<Button
|
||||||
|
key={option}
|
||||||
|
size="small"
|
||||||
|
variant={selected === option ? 'contained' : 'outlined'}
|
||||||
|
onClick={() => onChange(option)}
|
||||||
|
sx={{ textTransform: 'none' }}
|
||||||
|
>
|
||||||
|
{option}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default TimeFrameSelector;
|
||||||
215
src/components/Home/Analytics&Reporting/TopSellingProduct.js
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import { useMediaQuery } from '@mui/material';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Paper,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Chip,
|
||||||
|
Pagination,
|
||||||
|
Button,
|
||||||
|
Avatar,
|
||||||
|
TableContainer
|
||||||
|
} from '@mui/material';
|
||||||
|
import TuneIcon from '@mui/icons-material/Tune';
|
||||||
|
import { green } from '@mui/material/colors';
|
||||||
|
import AssignmentIcon from '@mui/icons-material/Assignment';
|
||||||
|
|
||||||
|
const TopSellingProduct = ({ data = [] }) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const itemsPerPage = 5;
|
||||||
|
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
|
||||||
|
const pageCount = Math.ceil(data.length / itemsPerPage);
|
||||||
|
const paginatedData = data.slice(
|
||||||
|
(currentPage - 1) * itemsPerPage,
|
||||||
|
currentPage * itemsPerPage
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper sx={{
|
||||||
|
borderRadius: 2,
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: { xs: '100%', md: '115vh' },
|
||||||
|
height: { xs: 'auto', md: '100vh' },
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
overflow: 'hidden',
|
||||||
|
boxShadow: theme.shadows[1]
|
||||||
|
}}>
|
||||||
|
{/* العنوان وزر الفلاتر */}
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
justifyContent="space-between"
|
||||||
|
alignItems="center"
|
||||||
|
p={{ xs: 1, sm: 2 }}
|
||||||
|
sx={{ backgroundColor: theme.palette.background.paper }}
|
||||||
|
>
|
||||||
|
<Typography variant="h6" sx={{ fontSize: { xs: '1rem', sm: '1.25rem' } }}>
|
||||||
|
Top Selling Product
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
fontSize: { xs: '12px', sm: '16px' },
|
||||||
|
fontWeight: 500,
|
||||||
|
border: '1px solid #e0e0e0',
|
||||||
|
color: '#667085',
|
||||||
|
textTransform: 'none',
|
||||||
|
p: { xs: '4px 8px', sm: '6px 16px' }
|
||||||
|
}}
|
||||||
|
startIcon={<TuneIcon fontSize={isMobile ? 'small' : 'medium'} />}
|
||||||
|
>
|
||||||
|
{isMobile ? '' : 'Filters'}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* جدول البيانات */}
|
||||||
|
<TableContainer
|
||||||
|
sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
overflowX: 'auto',
|
||||||
|
maxHeight: { xs: '60vh', md: 'calc(100vh - 160px)' },
|
||||||
|
'&::-webkit-scrollbar': { height: 4 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Table
|
||||||
|
size={isMobile ? 'small' : 'medium'}
|
||||||
|
sx={{
|
||||||
|
minWidth: 650,
|
||||||
|
'& .MuiTableCell-root': {
|
||||||
|
borderBottom: '1px solid #e0e0e0',
|
||||||
|
py: { xs: 0.5, sm: 1.5 },
|
||||||
|
px: { xs: 0.5, sm: 2 },
|
||||||
|
},
|
||||||
|
'& thead .MuiTableCell-root': {
|
||||||
|
borderBottom: 'none',
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: { xs: '11px', sm: '14px' },
|
||||||
|
px: { xs: 0.5, sm: 2 },
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TableHead sx={{ backgroundColor: '#F0F1F3' }}>
|
||||||
|
<TableRow sx={{ height: { xs: '6vh', sm: '10vh' } }}>
|
||||||
|
<TableCell>Product</TableCell>
|
||||||
|
{!isMobile && <TableCell>Sales</TableCell>}
|
||||||
|
<TableCell>Amount</TableCell>
|
||||||
|
{!isMobile && <TableCell>Price</TableCell>}
|
||||||
|
<TableCell>Status</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{paginatedData.map((row, i) => (
|
||||||
|
<TableRow key={i} sx={{ height: { xs: '8vh', sm: '13vh' } }}>
|
||||||
|
<TableCell>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: { xs: 1, sm: 2 } }}>
|
||||||
|
<Avatar
|
||||||
|
sx={{
|
||||||
|
bgcolor: green[50],
|
||||||
|
width: { xs: 28, sm: 40 },
|
||||||
|
height: { xs: 28, sm: 40 }
|
||||||
|
}}
|
||||||
|
variant="rounded"
|
||||||
|
>
|
||||||
|
<AssignmentIcon fontSize={isMobile ? 'small' : 'medium'} />
|
||||||
|
</Avatar>
|
||||||
|
<Box sx={{
|
||||||
|
fontSize: { xs: '11px', sm: '14px' },
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
maxWidth: { xs: '80px', sm: '200px' }
|
||||||
|
}}>
|
||||||
|
{row.product}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</TableCell>
|
||||||
|
{!isMobile && <TableCell sx={{ fontSize: { xs: '11px', sm: '14px' } }}>{row.sales}</TableCell>}
|
||||||
|
<TableCell sx={{ fontSize: { xs: '11px', sm: '14px' } }}>${row.amount.toLocaleString()}</TableCell>
|
||||||
|
{!isMobile && <TableCell sx={{ fontSize: { xs: '11px', sm: '14px' } }}>${row.price}</TableCell>}
|
||||||
|
<TableCell>
|
||||||
|
<Chip
|
||||||
|
label={isMobile ? row.status.substring(0, 3) : row.status}
|
||||||
|
size={isMobile ? 'small' : 'medium'}
|
||||||
|
sx={{
|
||||||
|
fontSize: { xs: '10px', sm: '14px' },
|
||||||
|
fontWeight: 600,
|
||||||
|
backgroundColor:
|
||||||
|
row.status === 'Published' ? '#E7F4EE' :
|
||||||
|
row.status === 'Low Stock' ? '#FDF1E8' :
|
||||||
|
row.status === 'Out of Stock' ? '#FFCDD2' : '#E0E0E0',
|
||||||
|
color:
|
||||||
|
row.status === 'Published' ? '#0D894F' :
|
||||||
|
row.status === 'Low Stock' ? '#E46A11' :
|
||||||
|
row.status === 'Out of Stock' ? '#C62828' : '#424242',
|
||||||
|
minWidth: { xs: '50px', sm: '100px' }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
|
||||||
|
{/* التذييل مع الترقيم */}
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
justifyContent="space-between"
|
||||||
|
alignItems="center"
|
||||||
|
p={{ xs: 1, sm: 2 }}
|
||||||
|
sx={{
|
||||||
|
position: 'sticky',
|
||||||
|
bottom: 0,
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
|
borderTop: '1px solid #f0f0f0',
|
||||||
|
zIndex: 1
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="text.secondary"
|
||||||
|
sx={{
|
||||||
|
fontSize: { xs: '11px', sm: '14px' },
|
||||||
|
whiteSpace: 'nowrap'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Showing {(currentPage - 1) * itemsPerPage + 1} to {Math.min(currentPage * itemsPerPage, data.length)} of {data.length}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Pagination
|
||||||
|
count={pageCount}
|
||||||
|
page={currentPage}
|
||||||
|
onChange={(event, value) => setCurrentPage(value)}
|
||||||
|
size={isMobile ? 'small' : 'medium'}
|
||||||
|
sx={{
|
||||||
|
'& .MuiPaginationItem-root': {
|
||||||
|
fontSize: { xs: '12px', sm: '14px' },
|
||||||
|
minWidth: { xs: 24, sm: 32 },
|
||||||
|
height: { xs: 24, sm: 32 },
|
||||||
|
backgroundColor: '#FFECE0',
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
borderRadius: '8px',
|
||||||
|
'&.Mui-selected': {
|
||||||
|
backgroundColor: '#FFB088',
|
||||||
|
color: '#fff',
|
||||||
|
},
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: '#FFD6B5',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TopSellingProduct;
|
||||||
210
src/components/Home/AppBar.js
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
AppBar,
|
||||||
|
Toolbar,
|
||||||
|
Typography,
|
||||||
|
Box,
|
||||||
|
IconButton,
|
||||||
|
Divider,
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
Autocomplete,
|
||||||
|
TextField,
|
||||||
|
InputAdornment,
|
||||||
|
useTheme,
|
||||||
|
useMediaQuery,
|
||||||
|
} from '@mui/material';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import MenuIcon from '@mui/icons-material/Menu';
|
||||||
|
import NotificationsOutlinedIcon from '@mui/icons-material/NotificationsOutlined';
|
||||||
|
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||||
|
import SearchIcon from '@mui/icons-material/Search';
|
||||||
|
|
||||||
|
const top100Films = [
|
||||||
|
{ title: 'The Shawshank Redemption' },
|
||||||
|
{ title: 'The Godfather' },
|
||||||
|
{ title: 'The Dark Knight' },
|
||||||
|
{ title: 'Pulp Fiction' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const KitchPlusAppBar = ({ onDrawerToggle, sidebarOpen, isMobile }) => {
|
||||||
|
const location = useLocation();
|
||||||
|
const theme = useTheme();
|
||||||
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
const isMediumScreen = useMediaQuery(theme.breakpoints.between('sm', 'md'));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppBar
|
||||||
|
sx={{
|
||||||
|
height: { xs: 56, sm: 64, md: 66 },
|
||||||
|
backgroundColor: '#F6F6F6',
|
||||||
|
color: 'black',
|
||||||
|
boxShadow: 'none',
|
||||||
|
borderBottom: '1px solid #e0e0e0',
|
||||||
|
position: 'sticky',
|
||||||
|
top: 0,
|
||||||
|
zIndex: theme.zIndex.appBar,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Toolbar
|
||||||
|
sx={{
|
||||||
|
px: { xs: 2, sm: 3, md: '24px' },
|
||||||
|
minHeight: { xs: '56px !important', sm: '64px !important' },
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Left side with toggle button */}
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
{/* Toggle button for mobile/tablet */}
|
||||||
|
{(isMobile || isMediumScreen) && (
|
||||||
|
<IconButton
|
||||||
|
color="inherit"
|
||||||
|
aria-label="open drawer"
|
||||||
|
edge="start"
|
||||||
|
onClick={onDrawerToggle}
|
||||||
|
sx={{ mr: 2 }}
|
||||||
|
>
|
||||||
|
<MenuIcon />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{location.pathname === '/dashboard' ? (
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
component="div"
|
||||||
|
sx={{
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: { xs: '18px', sm: '20px', md: '24px' },
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
maxWidth: { xs: '200px', sm: 'none' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Welcome to KitchPlus
|
||||||
|
</Typography>
|
||||||
|
) : (
|
||||||
|
<Autocomplete
|
||||||
|
sx={{
|
||||||
|
width: { xs: '200px', sm: '250px', md: '300px' },
|
||||||
|
borderRadius: '8px',
|
||||||
|
}}
|
||||||
|
freeSolo
|
||||||
|
id="free-solo-2-demo"
|
||||||
|
disableClearable
|
||||||
|
options={top100Films.map((option) => option.title)}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
placeholder="Search"
|
||||||
|
InputProps={{
|
||||||
|
...params.InputProps,
|
||||||
|
type: 'search',
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<SearchIcon sx={{ color: '#667085' }} />
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
'& .MuiInputBase-root': {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
height: { xs: 36, sm: 38, md: 40 },
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Right side */}
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: { xs: 0.8, sm: 1, md: 1.5 } }}>
|
||||||
|
{location.pathname === '/dashboard' && !isSmallScreen && (
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
display: { xs: 'none', sm: 'none', md: 'flex' }, // هذا السطر يخفي الزر عند xs و sm ويظهره من md وما فوق
|
||||||
|
color: 'white',
|
||||||
|
height: { xs: 32, sm: 36, md: 40 },
|
||||||
|
mr: { xs: '6px', sm: '8px', md: '10px' },
|
||||||
|
backgroundColor: '#61677F',
|
||||||
|
borderRadius: '8px',
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: { xs: '12px', sm: '13px', md: '14px' },
|
||||||
|
textTransform: 'none',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isMediumScreen ? 'Switch Company' : 'Switch Company Profits'}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{location.pathname === '/dashboard' && (
|
||||||
|
<Divider
|
||||||
|
orientation="vertical"
|
||||||
|
flexItem
|
||||||
|
sx={{
|
||||||
|
height: { xs: 30, sm: 36, md: 40 },
|
||||||
|
alignSelf: 'center',
|
||||||
|
mx: 1 // إضافة هامش أفقي إذا لزم الأمر
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<IconButton color="#667085" size={isSmallScreen ? 'small' : 'medium'}>
|
||||||
|
<NotificationsOutlinedIcon fontSize={isSmallScreen ? 'small' : 'medium'} />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<Divider
|
||||||
|
orientation="vertical"
|
||||||
|
flexItem
|
||||||
|
sx={{
|
||||||
|
height: { xs: 30, sm: 36, md: 40 },
|
||||||
|
alignSelf: 'center'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Avatar
|
||||||
|
alt="Admin"
|
||||||
|
src="/images/waitress3.png"
|
||||||
|
sx={{
|
||||||
|
width: { xs: 28, sm: 32, md: 40 },
|
||||||
|
height: { xs: 28, sm: 32, md: 40 }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{!isSmallScreen && (
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
sx={{
|
||||||
|
ml: { sm: 0.5, md: 1 },
|
||||||
|
color: '#61677F',
|
||||||
|
fontSize: { xs: '12px', sm: '13px', md: '14px' },
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
maxWidth: { xs: '100px', sm: '120px', md: 'none' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Admin@gmail.com
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
color="inherit"
|
||||||
|
sx={{
|
||||||
|
mt: 0.5,
|
||||||
|
color: '#A6ACB8',
|
||||||
|
padding: { xs: '4px', sm: '8px' }
|
||||||
|
}}
|
||||||
|
size={isSmallScreen ? 'small' : 'medium'}
|
||||||
|
>
|
||||||
|
<KeyboardArrowDownIcon fontSize={isSmallScreen ? 'small' : 'medium'} />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default KitchPlusAppBar;
|
||||||
105
src/components/Home/Cashier/Cashier.js
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Box, useTheme, useMediaQuery, Typography } from '@mui/material';
|
||||||
|
import KitchPlusAppBar from '../AppBar';
|
||||||
|
import Sidebar from '../SideHome';
|
||||||
|
|
||||||
|
const drawerWidth = 230;
|
||||||
|
|
||||||
|
const Cashier = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
const [hasProducts, setHasProducts] = useState(false); // حالة لتتبع وجود المنتجات
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(!isMobile);
|
||||||
|
|
||||||
|
// محاكاة للتحقق من وجود المنتجات (استبدل هذا بمنطقك الفعلي)
|
||||||
|
useEffect(() => {
|
||||||
|
// هنا يجب استبدال هذا بمنطق فعلي للتحقق من وجود المنتجات
|
||||||
|
// مثلاً استدعاء API أو التحقق من state
|
||||||
|
const checkProducts = async () => {
|
||||||
|
// محاكاة لاستدعاء API
|
||||||
|
const productsExist = await checkIfProductsExist(); // استبدل هذه الدالة بمنطقك الفعلي
|
||||||
|
setHasProducts(productsExist);
|
||||||
|
};
|
||||||
|
|
||||||
|
checkProducts();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// دالة مساعدة لمحاكاة التحقق من المنتجات (استبدلها بمنطقك الفعلي)
|
||||||
|
const checkIfProductsExist = async () => {
|
||||||
|
// محاكاة - يمكن أن يكون هذا استدعاء لـ API أو تحقق من state
|
||||||
|
// return true;
|
||||||
|
return false; // غير هذه القيمة حسب منطقك
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (window.innerWidth >= theme.breakpoints.values.md) {
|
||||||
|
setSidebarOpen(true);
|
||||||
|
} else {
|
||||||
|
setSidebarOpen(false);
|
||||||
|
}
|
||||||
|
}, [theme.breakpoints.values.md]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
if (window.innerWidth >= theme.breakpoints.values.md) {
|
||||||
|
setSidebarOpen(true);
|
||||||
|
} else {
|
||||||
|
setSidebarOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, [theme.breakpoints.values.md]);
|
||||||
|
|
||||||
|
const handleDrawerToggle = () => {
|
||||||
|
setSidebarOpen(!sidebarOpen);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
height: '100vh',
|
||||||
|
backgroundColor:'#F6F6F6',
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}>
|
||||||
|
<Sidebar
|
||||||
|
open={sidebarOpen}
|
||||||
|
onClose={handleDrawerToggle}
|
||||||
|
isMobile={isMobile}
|
||||||
|
drawerWidth={drawerWidth}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Box sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
width: {
|
||||||
|
xs: '100%',
|
||||||
|
sm: '100%',
|
||||||
|
md: '100%'
|
||||||
|
},
|
||||||
|
marginLeft: {
|
||||||
|
xs: 0,
|
||||||
|
sm: sidebarOpen ? `${drawerWidth}px` : 0,
|
||||||
|
md: 0
|
||||||
|
},
|
||||||
|
transition: theme.transitions.create(['width'], {
|
||||||
|
easing: theme.transitions.easing.sharp,
|
||||||
|
duration: theme.transitions.duration.leavingScreen,
|
||||||
|
}),
|
||||||
|
}}>
|
||||||
|
<KitchPlusAppBar
|
||||||
|
onDrawerToggle={handleDrawerToggle}
|
||||||
|
sidebarOpen={sidebarOpen}
|
||||||
|
isMobile={isMobile}
|
||||||
|
/>
|
||||||
|
<Typography>Cashier</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Cashier;
|
||||||
105
src/components/Home/CreateYourRestaurant/CreateRestaurant.js
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Box, useTheme, useMediaQuery, Typography } from '@mui/material';
|
||||||
|
import KitchPlusAppBar from '../AppBar';
|
||||||
|
import Sidebar from '../SideHome';
|
||||||
|
|
||||||
|
const drawerWidth = 230;
|
||||||
|
|
||||||
|
const CreateRestaurant = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
const [hasProducts, setHasProducts] = useState(false); // حالة لتتبع وجود المنتجات
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(!isMobile);
|
||||||
|
|
||||||
|
// محاكاة للتحقق من وجود المنتجات (استبدل هذا بمنطقك الفعلي)
|
||||||
|
useEffect(() => {
|
||||||
|
// هنا يجب استبدال هذا بمنطق فعلي للتحقق من وجود المنتجات
|
||||||
|
// مثلاً استدعاء API أو التحقق من state
|
||||||
|
const checkProducts = async () => {
|
||||||
|
// محاكاة لاستدعاء API
|
||||||
|
const productsExist = await checkIfProductsExist(); // استبدل هذه الدالة بمنطقك الفعلي
|
||||||
|
setHasProducts(productsExist);
|
||||||
|
};
|
||||||
|
|
||||||
|
checkProducts();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// دالة مساعدة لمحاكاة التحقق من المنتجات (استبدلها بمنطقك الفعلي)
|
||||||
|
const checkIfProductsExist = async () => {
|
||||||
|
// محاكاة - يمكن أن يكون هذا استدعاء لـ API أو تحقق من state
|
||||||
|
// return true;
|
||||||
|
return false; // غير هذه القيمة حسب منطقك
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (window.innerWidth >= theme.breakpoints.values.md) {
|
||||||
|
setSidebarOpen(true);
|
||||||
|
} else {
|
||||||
|
setSidebarOpen(false);
|
||||||
|
}
|
||||||
|
}, [theme.breakpoints.values.md]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
if (window.innerWidth >= theme.breakpoints.values.md) {
|
||||||
|
setSidebarOpen(true);
|
||||||
|
} else {
|
||||||
|
setSidebarOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, [theme.breakpoints.values.md]);
|
||||||
|
|
||||||
|
const handleDrawerToggle = () => {
|
||||||
|
setSidebarOpen(!sidebarOpen);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
height: '100vh',
|
||||||
|
backgroundColor: '#F6F6F6',
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}>
|
||||||
|
<Sidebar
|
||||||
|
open={sidebarOpen}
|
||||||
|
onClose={handleDrawerToggle}
|
||||||
|
isMobile={isMobile}
|
||||||
|
drawerWidth={drawerWidth}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Box sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
width: {
|
||||||
|
xs: '100%',
|
||||||
|
sm: '100%',
|
||||||
|
md: '100%'
|
||||||
|
},
|
||||||
|
marginLeft: {
|
||||||
|
xs: 0,
|
||||||
|
sm: sidebarOpen ? `${drawerWidth}px` : 0,
|
||||||
|
md: 0
|
||||||
|
},
|
||||||
|
transition: theme.transitions.create(['width'], {
|
||||||
|
easing: theme.transitions.easing.sharp,
|
||||||
|
duration: theme.transitions.duration.leavingScreen,
|
||||||
|
}),
|
||||||
|
}}>
|
||||||
|
<KitchPlusAppBar
|
||||||
|
onDrawerToggle={handleDrawerToggle}
|
||||||
|
sidebarOpen={sidebarOpen}
|
||||||
|
isMobile={isMobile}
|
||||||
|
/>
|
||||||
|
<Typography>CreateYourRestaurant</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CreateRestaurant;
|
||||||
107
src/components/Home/Dashboard/Dashboard.js
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Box, useTheme, useMediaQuery, Skeleton } from '@mui/material';
|
||||||
|
import KitchPlusAppBar from '../AppBar';
|
||||||
|
import Sidebar from '../SideHome';
|
||||||
|
import DashbordContect from './DashboardContcet';
|
||||||
|
import NoProdectDash from './NoProdectDash';
|
||||||
|
|
||||||
|
const drawerWidth = 230;
|
||||||
|
|
||||||
|
const Dashboard = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
const [hasProducts, setHasProducts] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(!isMobile);
|
||||||
|
|
||||||
|
// محاكاة التحقق من المنتجات
|
||||||
|
useEffect(() => {
|
||||||
|
const checkProducts = async () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
const productsExist = await checkIfProductsExist(); // استبدل بمنطقك
|
||||||
|
setHasProducts(productsExist);
|
||||||
|
setIsLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
checkProducts();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const checkIfProductsExist = async () => {
|
||||||
|
return new Promise((resolve) => setTimeout(() => resolve(true), 1500)); // محاكاة تأخير
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (window.innerWidth >= theme.breakpoints.values.md) {
|
||||||
|
setSidebarOpen(true);
|
||||||
|
} else {
|
||||||
|
setSidebarOpen(false);
|
||||||
|
}
|
||||||
|
}, [theme.breakpoints.values.md]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
if (window.innerWidth >= theme.breakpoints.values.md) {
|
||||||
|
setSidebarOpen(true);
|
||||||
|
} else {
|
||||||
|
setSidebarOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, [theme.breakpoints.values.md]);
|
||||||
|
|
||||||
|
const handleDrawerToggle = () => {
|
||||||
|
setSidebarOpen(!sidebarOpen);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ display: 'flex', height: '100vh', backgroundColor: '#F6F6F6', overflow: 'hidden' }}>
|
||||||
|
<Sidebar open={sidebarOpen} onClose={handleDrawerToggle} isMobile={isMobile} drawerWidth={drawerWidth} />
|
||||||
|
|
||||||
|
<Box sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
width: { xs: '100%', sm: '100%', md: '100%' },
|
||||||
|
marginLeft: { xs: 0, sm: sidebarOpen ? `${drawerWidth}px` : 0, md: 0 },
|
||||||
|
transition: theme.transitions.create(['width'], {
|
||||||
|
easing: theme.transitions.easing.sharp,
|
||||||
|
duration: theme.transitions.duration.leavingScreen,
|
||||||
|
}),
|
||||||
|
}}>
|
||||||
|
<KitchPlusAppBar onDrawerToggle={handleDrawerToggle} sidebarOpen={sidebarOpen} isMobile={isMobile} />
|
||||||
|
|
||||||
|
<Box sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
width: sidebarOpen ? 'calc(100% - 20px)' : '100%',
|
||||||
|
pt: { xs: 0.5, sm: 1 },
|
||||||
|
mt: { xs: 1, sm: 2 },
|
||||||
|
overflowY: 'auto',
|
||||||
|
pl: { xs: 0, sm: 2 },
|
||||||
|
pr: { xs: 1, sm: 2 },
|
||||||
|
pb: { xs: 1, sm: 2 },
|
||||||
|
scrollbarWidth: 'none',
|
||||||
|
'&::-webkit-scrollbar': { display: 'none' },
|
||||||
|
transition: theme.transitions.create(['margin'], {
|
||||||
|
easing: theme.transitions.easing.sharp,
|
||||||
|
duration: theme.transitions.duration.leavingScreen,
|
||||||
|
}),
|
||||||
|
}}>
|
||||||
|
{isLoading ? (
|
||||||
|
<>
|
||||||
|
<Skeleton variant="rectangular" height={50} sx={{ mb: 2 }} />
|
||||||
|
<Skeleton variant="rectangular" height={200} sx={{ mb: 2 }} />
|
||||||
|
<Skeleton variant="rectangular" height={300} sx={{ mb: 2 }} />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
hasProducts ? <DashbordContect /> : <NoProdectDash />
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Dashboard;
|
||||||
395
src/components/Home/Dashboard/DashboardContcet.js
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Box, Button, Card, CardContent, Stack, Typography, useMediaQuery } from '@mui/material';
|
||||||
|
import AirportShuttleIcon from '@mui/icons-material/AirportShuttle';
|
||||||
|
import CampaignIcon from '@mui/icons-material/Campaign';
|
||||||
|
import Inventory2Icon from '@mui/icons-material/Inventory2';
|
||||||
|
import DeveloperBoardIcon from '@mui/icons-material/DeveloperBoard';
|
||||||
|
import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
|
import OrderStatusCard from './OrderStatusCard';
|
||||||
|
import StatisticsCard from './StatisticsCard';
|
||||||
|
import RecentActivity from './RecentActivity';
|
||||||
|
|
||||||
|
const IconCircle = ({ children, bgColor = '#DEDEFA', outerColor = '#EFEFFD' }) => (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'relative',
|
||||||
|
width: { xs: 40, sm: 45, md: 50 },
|
||||||
|
height: { xs: 43, sm: 48, md: 53 },
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
width: { xs: 32, sm: 36, md: 40 },
|
||||||
|
height: { xs: 35, sm: 39, md: 43 },
|
||||||
|
borderRadius: '50%',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
backgroundColor: outerColor,
|
||||||
|
zIndex: 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: { xs: 24, sm: 27, md: 30 },
|
||||||
|
height: { xs: 27, sm: 30, md: 33 },
|
||||||
|
backgroundColor: bgColor,
|
||||||
|
borderRadius: '50%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
zIndex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
|
const StatusCard = ({
|
||||||
|
icon,
|
||||||
|
statusText,
|
||||||
|
statusColor,
|
||||||
|
iconColor,
|
||||||
|
outerColor,
|
||||||
|
innerColor,
|
||||||
|
height = {
|
||||||
|
xs: 'calc(140px + 0.5vh)',
|
||||||
|
sm: 'calc(150px + 0.5vh)',
|
||||||
|
md: 'calc(162px + 0.5vh)'
|
||||||
|
},
|
||||||
|
width = {
|
||||||
|
xs: 'min(90%, 600px)', // تقليل من 90% إلى 85% والحد الأقصى من 300px إلى 280px
|
||||||
|
sm: 'clamp(220px, 23vw, 280px)', // تقليل جميع القيم
|
||||||
|
md: 'clamp(220px, 19vw, 300px)'
|
||||||
|
},
|
||||||
|
transition = 'width 0.3s ease',
|
||||||
|
iconSpacing = { xs: 6, sm: 8, md: 12 },
|
||||||
|
extraButton,
|
||||||
|
statusButtonWidth,
|
||||||
|
title = 'Point Of Sale',
|
||||||
|
}) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card sx={{
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
p: 0,
|
||||||
|
pb: 2,
|
||||||
|
borderRadius: '8px',
|
||||||
|
boxShadow: 'none',
|
||||||
|
minWidth: { xs: 180, sm: 220 }
|
||||||
|
}}>
|
||||||
|
<CardContent>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: iconSpacing }}>
|
||||||
|
<IconCircle bgColor={innerColor} outerColor={outerColor}>
|
||||||
|
{React.cloneElement(icon, { sx: { color: iconColor, fontSize: { xs: 16, sm: 18, md: 20 } } })}
|
||||||
|
</IconCircle>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: '#E7F4EE',
|
||||||
|
color: statusColor,
|
||||||
|
textTransform: 'none',
|
||||||
|
boxShadow: 'none',
|
||||||
|
borderRadius: '100px',
|
||||||
|
width: statusButtonWidth || 'auto',
|
||||||
|
fontSize: { xs: '0.7rem', sm: '0.8rem', md: '0.9rem' },
|
||||||
|
px: { xs: 1, sm: 1.5 },
|
||||||
|
py: 0.5
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{statusText}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
gutterBottom
|
||||||
|
mt={1.5}
|
||||||
|
sx={{
|
||||||
|
color: '#667085',
|
||||||
|
fontSize: { xs: '14px', sm: '15px', md: '16px' },
|
||||||
|
fontWeight: 500
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mt: 2 }}>
|
||||||
|
{extraButton ? extraButton : <Box />}
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: '#F7F7F7',
|
||||||
|
width: { xs: '26px', sm: '28px', md: '30px' },
|
||||||
|
height: { xs: '26px', sm: '28px', md: '30px' },
|
||||||
|
minWidth: '0',
|
||||||
|
padding: 0,
|
||||||
|
borderRadius: '12px',
|
||||||
|
boxShadow: 'none',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: '#e0e0e0',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ArrowOutwardIcon
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
width: { xs: '16px', sm: '18px', md: '20px' },
|
||||||
|
height: { xs: '16px', sm: '18px', md: '20px' },
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const DashboardContect = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
const isMediumScreen = useMediaQuery(theme.breakpoints.between('sm', 'md'));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Header Section */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: { xs: 'flex-start', sm: 'center', md: 'center' },
|
||||||
|
mb: 3,
|
||||||
|
pl: 1,
|
||||||
|
pr: { xs: 1, sm: 3 },
|
||||||
|
flexDirection: { xs: 'column', sm: 'row', md: 'row' },
|
||||||
|
gap: { xs: 2, sm: 0 }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Title */}
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
sx={{
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: { xs: '20px', sm: '22px', md: '24px' },
|
||||||
|
color: '#121212'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Dashboard
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Buttons */}
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: { xs: 1, sm: 2 },
|
||||||
|
flexWrap: { xs: 'wrap', sm: 'nowrap' },
|
||||||
|
width: { xs: '100%', sm: 'auto' },
|
||||||
|
justifyContent: { xs: 'space-between', sm: 'space-between', md: 'flex-end' }
|
||||||
|
}}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
textTransform: 'none',
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
boxShadow: 'none',
|
||||||
|
borderRadius: '8px',
|
||||||
|
height: '40px',
|
||||||
|
width: { xs: '48%', sm: '130px', md: '156px' },
|
||||||
|
fontSize: { xs: '12px', sm: '13px', md: '14px' },
|
||||||
|
fontWeight: 600,
|
||||||
|
p: 0,
|
||||||
|
m: 0,
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
minWidth: 'unset'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AddIcon sx={{ fontSize: { xs: 16, sm: 18, md: 20 } }} />
|
||||||
|
{!isSmallScreen && 'Add New Menu'}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
textTransform: 'none',
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: '#5F6868',
|
||||||
|
boxShadow: 'none',
|
||||||
|
borderRadius: '8px',
|
||||||
|
height: '40px',
|
||||||
|
width: { xs: '48%', sm: '150px', md: '208px' },
|
||||||
|
fontSize: { xs: '12px', sm: '13px', md: '14px' },
|
||||||
|
fontWeight: 600,
|
||||||
|
p: 0,
|
||||||
|
m: 0,
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
minWidth: 'unset'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isSmallScreen ? 'Marketing' : 'Start Marketing '}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
textTransform: 'none',
|
||||||
|
color: 'black',
|
||||||
|
backgroundColor: '#FFFFFF',
|
||||||
|
boxShadow: 'none',
|
||||||
|
borderRadius: '8px',
|
||||||
|
height: '40px',
|
||||||
|
width: { xs: '100%', sm: '120px', md: '141px' },
|
||||||
|
fontSize: { xs: '12px', sm: '13px', md: '14px' },
|
||||||
|
fontWeight: 600,
|
||||||
|
p: 0,
|
||||||
|
m: 0,
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
minWidth: 'unset'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Check Inventory
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Status Cards */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
|
||||||
|
display: 'flex',
|
||||||
|
gap: { xs: 1.5, sm: 2 },
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
justifyContent: { xs: 'center', sm: 'flex-start' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<StatusCard
|
||||||
|
icon={<DeveloperBoardIcon />}
|
||||||
|
statusText="Active"
|
||||||
|
statusColor="#0D894F"
|
||||||
|
iconColor="#057DEC"
|
||||||
|
innerColor="#DEDEFA"
|
||||||
|
outerColor="#EFEFFD"
|
||||||
|
iconSpacing={{ xs: 6, sm: 8, md: 12 }}
|
||||||
|
extraButton={
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: '#F6F6F6',
|
||||||
|
color: '#5F6868',
|
||||||
|
textTransform: 'none',
|
||||||
|
fontSize: { xs: '0.7rem', sm: '0.8rem', md: '0.85rem' },
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: { xs: '2px 8px', sm: '4px 12px' },
|
||||||
|
boxShadow: 'none',
|
||||||
|
fontWeight: 600,
|
||||||
|
height: { xs: 32, sm: 36, md: 40 },
|
||||||
|
width: { xs: 70, sm: 80, md: 85 },
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Register
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<StatusCard
|
||||||
|
icon={<Inventory2Icon />}
|
||||||
|
statusText="Active"
|
||||||
|
statusColor="#0D894F"
|
||||||
|
iconColor="#34B405"
|
||||||
|
innerColor="#E1F6DF"
|
||||||
|
outerColor="#EDFBE9"
|
||||||
|
iconSpacing={{ xs: 6, sm: 8, md: 12 }}
|
||||||
|
title="Inventory"
|
||||||
|
/>
|
||||||
|
<StatusCard
|
||||||
|
icon={<CampaignIcon />}
|
||||||
|
statusText="Pending"
|
||||||
|
statusColor="#BBB50F"
|
||||||
|
iconColor="#990463"
|
||||||
|
innerColor="#FEC8EA"
|
||||||
|
outerColor="#FFE3F5"
|
||||||
|
iconSpacing={{ xs: 6, sm: 8, md: 12 }}
|
||||||
|
title="Marketing"
|
||||||
|
/>
|
||||||
|
<StatusCard
|
||||||
|
icon={<AirportShuttleIcon />}
|
||||||
|
statusText="Action Need"
|
||||||
|
statusColor="#EF0A0A"
|
||||||
|
iconColor="#069797"
|
||||||
|
outerColor="#DBFBFB"
|
||||||
|
innerColor="#B5F5F5"
|
||||||
|
iconSpacing={{ xs: 3, sm: 5, md: 7 }}
|
||||||
|
title="Delivery"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* OrderStatusCard/ StatisticsCard */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
flexDirection: { xs: 'column', sm: 'row' },
|
||||||
|
gap: { xs: 1, sm: 1, md: 7 }, // gap مرن
|
||||||
|
mb: 1,
|
||||||
|
pl: 1,
|
||||||
|
pr: 1,
|
||||||
|
mt: 2,
|
||||||
|
ml: { xs: 2, sm: 0 },
|
||||||
|
mr: 2,
|
||||||
|
flexShrink: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* OrderStatusCard */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
flexGrow: 0,
|
||||||
|
width: { xs: '100%', sm: '35%', md: '30%' },
|
||||||
|
minWidth: 220,
|
||||||
|
ml: { xs: 0, sm: -1 },
|
||||||
|
flexShrink: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<OrderStatusCard />
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* StatisticsCard */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
minWidth: 0,
|
||||||
|
ml: { xs: 0, sm: 2 },
|
||||||
|
// backgroundColor:'red'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<StatisticsCard />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
|
{/* RecentActivity */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
mr: { xs: 4, sm: 3 ,md:0 },
|
||||||
|
ml: { xs: 2, sm: 0 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RecentActivity />
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DashboardContect;
|
||||||
109
src/components/Home/Dashboard/NoProdectDash.js
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Typography,
|
||||||
|
useMediaQuery
|
||||||
|
} from '@mui/material';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
|
|
||||||
|
const NoProdectDash = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Header Section */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: { xs: 'flex-start', sm: 'center', md: 'center' },
|
||||||
|
mb: 3,
|
||||||
|
pl: 1,
|
||||||
|
pr: { xs: 1, sm: 3 },
|
||||||
|
flexDirection: { xs: 'column', sm: 'row', md: 'row' },
|
||||||
|
gap: { xs: 2, sm: 0 }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
sx={{
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: { xs: '20px', sm: '22px', md: '24px' },
|
||||||
|
color: '#121212'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Dashboard
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Empty State Content */}
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
boxShadow: 'none',
|
||||||
|
p: 4,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CardContent>
|
||||||
|
{/* Image Placeholder */}
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src="/images/compeoter.png"
|
||||||
|
alt="No products available"
|
||||||
|
sx={{
|
||||||
|
width: isSmallScreen ? 150 : 200,
|
||||||
|
height: 'auto',
|
||||||
|
mb: 1,
|
||||||
|
opacity: 0.8
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Title with colored "Sorry!" */}
|
||||||
|
<Typography
|
||||||
|
variant="h5"
|
||||||
|
sx={{
|
||||||
|
fontWeight: 400,
|
||||||
|
fontSize: { xs: '14px', md: '18px' },
|
||||||
|
mb: 2,
|
||||||
|
color: '#5F6868',
|
||||||
|
whiteSpace: 'pre-line' // هذا يسمح بكسر السطر عند المسافات
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box component="span" sx={{ fontWeight: 600, fontSize: '18px' }}>Sorry!</Box>{' '}
|
||||||
|
There is no campaign available.
|
||||||
|
Please initiate the {'\n'}creation of a new campaign.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Action Button */}
|
||||||
|
{/* <Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
sx={{
|
||||||
|
textTransform: 'none',
|
||||||
|
px: 4,
|
||||||
|
py: 1.5,
|
||||||
|
fontSize: '16px',
|
||||||
|
fontWeight: 600,
|
||||||
|
borderRadius: 2,
|
||||||
|
color:'white'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Create New Product
|
||||||
|
</Button> */}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NoProdectDash;
|
||||||
260
src/components/Home/Dashboard/OrderStatusCard.js
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Divider,
|
||||||
|
Chip,
|
||||||
|
useTheme,
|
||||||
|
IconButton,
|
||||||
|
useMediaQuery
|
||||||
|
} from '@mui/material';
|
||||||
|
import {
|
||||||
|
TrendingUp as TrendingUpIcon,
|
||||||
|
TrendingDown as TrendingDownIcon,
|
||||||
|
CheckCircle as CheckCircleIcon,
|
||||||
|
Cancel as CancelIcon,
|
||||||
|
Pending as PendingIcon
|
||||||
|
} from '@mui/icons-material';
|
||||||
|
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||||
|
import {
|
||||||
|
CircularProgressbar,
|
||||||
|
buildStyles
|
||||||
|
} from 'react-circular-progressbar';
|
||||||
|
import 'react-circular-progressbar/dist/styles.css';
|
||||||
|
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
|
||||||
|
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
|
||||||
|
// import { Box, IconButton, Paper, Typography, useTheme, useMediaQuery } from '@mui/material';
|
||||||
|
import {
|
||||||
|
|
||||||
|
ResponsiveContainer,
|
||||||
|
|
||||||
|
} from 'recharts';
|
||||||
|
|
||||||
|
|
||||||
|
const OrderStatusCard = ({
|
||||||
|
title = 'Order Status',
|
||||||
|
period = 'This Quarter',
|
||||||
|
progress = 70.5,
|
||||||
|
progressChange = '+10%',
|
||||||
|
progressDirection = 'up', // or 'down'
|
||||||
|
description = 'You succeeded in earning $240 today, it’s higher than yesterday',
|
||||||
|
completed = '$20k',
|
||||||
|
canceled = '$16k',
|
||||||
|
pending = '$1.5k'
|
||||||
|
}) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const progressColor = progressDirection === 'up' ? theme.palette.success.main : theme.palette.error.main;
|
||||||
|
const progressIcon = progressDirection === 'up' ? <TrendingUpIcon fontSize="small" /> : <TrendingDownIcon fontSize="small" />;
|
||||||
|
const highlightedDescription = description.replace(
|
||||||
|
/(\$\d+(?:\.\d+)?[kKmM]?)/g,
|
||||||
|
'<span style="color:#000;font-weight:500;">$1</span>'
|
||||||
|
);
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
const isTablet = useMediaQuery(theme.breakpoints.between('sm', 'md'));
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
width: { xs: '96%', sm: '94%', md: 360 },
|
||||||
|
height: 'auto',
|
||||||
|
borderRadius: 2,
|
||||||
|
boxShadow: '0px 4px 5px rgba(0, 0, 0, 0.1)',
|
||||||
|
pl: { xs: 1, sm: 1 },
|
||||||
|
pr: { xs: 1, sm: 1 },
|
||||||
|
pb: { xs: 1, sm: 1 },
|
||||||
|
pt: { xs: 0, sm: 0 },
|
||||||
|
|
||||||
|
position: 'relative' // إضافة هذه الخاصية
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ResponsiveContainer width="100%" height={isMobile ? '75vh' : isTablet ? '59vh' : 385}>
|
||||||
|
{/* زر الإجراءات في الزاوية العلوية اليمنى */}
|
||||||
|
<IconButton
|
||||||
|
aria-label="more-actions"
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 8,
|
||||||
|
right: 8,
|
||||||
|
color: '#667085'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MoreVertIcon />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<CardContent>
|
||||||
|
{/* Header */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
|
||||||
|
ml: 0 // هامش يسار لإفساح المجال للأيقونة
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
sx={{
|
||||||
|
fontSize: { xs: '16px', sm: '18px' },
|
||||||
|
fontWeight: 500
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: { xs: '12px', sm: '14px' },
|
||||||
|
fontWeight: 500,
|
||||||
|
color: '#667085'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{period}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Progress Circle */}
|
||||||
|
<Box sx={{ height: 120, mb: 2, position: 'relative' }}>
|
||||||
|
{/* تغيير النسبة تحت الدائرة */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '80%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
textAlign: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Chip
|
||||||
|
label={progressChange}
|
||||||
|
size="small"
|
||||||
|
icon={progressIcon}
|
||||||
|
sx={{
|
||||||
|
height: 22,
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
color: progressDirection === 'up' ? '#087443' : '#B42318',
|
||||||
|
backgroundColor: progressDirection === 'up' ? '#ECFDF3' : '#FEF3F2',
|
||||||
|
'.MuiChip-icon': {
|
||||||
|
color: progressDirection === 'up' ? '#087443' : '#B42318',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* دائرة التقدم */}
|
||||||
|
<Box sx={{ position: 'relative', width: '100%', maxWidth: 250, mx: 'auto' }}>
|
||||||
|
<CircularProgressbar
|
||||||
|
value={100}
|
||||||
|
circleRatio={0.5}
|
||||||
|
strokeWidth={5}
|
||||||
|
styles={buildStyles({
|
||||||
|
rotation: 0.75,
|
||||||
|
strokeLinecap: 'round',
|
||||||
|
trailColor: '#eee',
|
||||||
|
pathColor: '#eee',
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<Box sx={{ position: 'absolute', top: -1.5, left: 0, width: '100%', height: '100%' }}>
|
||||||
|
<CircularProgressbar
|
||||||
|
value={progress}
|
||||||
|
circleRatio={0.5}
|
||||||
|
strokeWidth={6}
|
||||||
|
styles={buildStyles({
|
||||||
|
rotation: 0.75,
|
||||||
|
strokeLinecap: 'round',
|
||||||
|
trailColor: 'transparent',
|
||||||
|
pathColor: theme.palette.primary.main,
|
||||||
|
textColor: 'transparent',
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* النص داخل الدائرة */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '22%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
fontSize: { xs: '18px', sm: '24px' },
|
||||||
|
fontWeight: 500,
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{`${progress}%`}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* الوصف */}
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
mb: 1,
|
||||||
|
mt: 5,
|
||||||
|
color: '#667085',
|
||||||
|
fontSize: { xs: '14px', sm: '16px' },
|
||||||
|
}}
|
||||||
|
dangerouslySetInnerHTML={{ __html: highlightedDescription }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Divider sx={{ my: 2 }} />
|
||||||
|
|
||||||
|
{/* الحقول الثلاثة (Completed / Canceled / Pending) */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
gap: { xs: 1, sm: 2 },
|
||||||
|
flexDirection: { xs: 'column', sm: 'row' },
|
||||||
|
ml: -1
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* لكل قسم: */}
|
||||||
|
{[{
|
||||||
|
label: 'Completed',
|
||||||
|
icon: <ArrowUpwardIcon color="success" fontSize="small" sx={{ mt: 0.2, ml: -1 }} />,
|
||||||
|
value: completed
|
||||||
|
}, {
|
||||||
|
label: 'Canceled',
|
||||||
|
icon: <ArrowDownwardIcon color="error" fontSize="small" sx={{ mt: 0.6, ml: -1 }} />,
|
||||||
|
value: canceled
|
||||||
|
}, {
|
||||||
|
label: 'Pending',
|
||||||
|
icon: <ArrowDownwardIcon color="warning" fontSize="small" sx={{ mt: 0.6, ml: -1 }} />,
|
||||||
|
value: pending
|
||||||
|
}].map(({ label, icon, value }, i) => (
|
||||||
|
<Box
|
||||||
|
key={i}
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
flex: 1,
|
||||||
|
mb: { xs: 1, sm: 0 }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{ color: '#667085', fontSize: '12px', fontWeight: 500, mb: 1 }}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Typography>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
||||||
|
{icon}
|
||||||
|
<Typography sx={{ color: '#333843', fontSize: { xs: '14px', sm: '16px',md:'24px'}, fontWeight: 500 }}>
|
||||||
|
{value}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OrderStatusCard;
|
||||||
107
src/components/Home/Dashboard/RecentActivity.js
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Paper,
|
||||||
|
Button,
|
||||||
|
Chip
|
||||||
|
} from '@mui/material';
|
||||||
|
// import LocalShippingIcon from '@mui/icons-material/LocalShipping';
|
||||||
|
// import InventoryIcon from '@mui/icons-material/Inventory';
|
||||||
|
// import AssignmentIcon from '@mui/icons-material/Assignment';
|
||||||
|
|
||||||
|
const RecentActivity = () => {
|
||||||
|
// Sample data
|
||||||
|
const activities = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
order: 'Order #1234 completed',
|
||||||
|
delivery: 'Delivery en route',
|
||||||
|
inventory: 'Low stock on item #567'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
order: 'Order #1235 completed',
|
||||||
|
delivery: 'Delivery delayed',
|
||||||
|
inventory: 'Low stock on item #890'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
order: 'Order #1236 completed',
|
||||||
|
delivery: 'Delivery arrived',
|
||||||
|
inventory: 'Out of stock on item #123'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ width: '93.5%', p: 3, backgroundColor: "white", borderRadius: 2, }}>
|
||||||
|
<Typography variant="h5" gutterBottom sx={{ fontWeight: 600, fontSize: '20px', mb: 2 }}>
|
||||||
|
Recent Activity
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<TableContainer component={Paper} sx={{ boxShadow: 'none', border: '1px solid #e0e0e0', borderRadius: 2 }}>
|
||||||
|
<Table sx={{ minWidth: 650 }} aria-label="recent activity table">
|
||||||
|
<TableHead sx={{ backgroundColor: '#f5f5f5', color: '#61677F' }}>
|
||||||
|
|
||||||
|
<TableRow sx={{ '& th': { borderBottom: 'none' } }}>
|
||||||
|
<TableCell sx={{ fontWeight: 500, fontSize: '16px', color: '#61677F' }}>New Orders</TableCell>
|
||||||
|
<TableCell sx={{ fontWeight: 500, fontSize: '16px', color: '#61677F' }}>Delivery Updates</TableCell>
|
||||||
|
<TableCell sx={{ fontWeight: 500, fontSize: '16px', color: '#61677F' }}>Inventory Alerts</TableCell>
|
||||||
|
<TableCell sx={{ fontWeight: 500, fontSize: '16px', color: '#61677F' }}>Actions</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{activities.map((activity) => (
|
||||||
|
<TableRow key={activity.id}>
|
||||||
|
<TableCell>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', color: '#4F5867', fontSize: '14px', fontWeight: 500 }}>
|
||||||
|
{activity.order}
|
||||||
|
</Box>
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
<TableCell>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', color: '#4F5867', fontSize: '14px', fontWeight: 500 }}>
|
||||||
|
{activity.delivery}
|
||||||
|
</Box>
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
<TableCell>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', color: '#4F5867', fontSize: '14px', fontWeight: 500 }}>
|
||||||
|
{activity.inventory}
|
||||||
|
</Box>
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
<TableCell sx={{ width: '28%' }} >
|
||||||
|
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||||
|
<Button
|
||||||
|
sx={{ color: 'white', borderRadius: '8px', fontWeight: 600, fontSize: '14px', height: '40px', width: '135px', textTransform: 'none' }}
|
||||||
|
variant="contained"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
Record Inventory
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
sx={{ fontWeight: 600, fontSize: '14px', borderRadius: '8px', height: '40px', textTransform: 'none' }}
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
Assign Task
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RecentActivity;
|
||||||
196
src/components/Home/Dashboard/StatisticsCard.js
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Box, IconButton, Paper, Typography, useTheme, useMediaQuery } from '@mui/material';
|
||||||
|
import {
|
||||||
|
LineChart,
|
||||||
|
Line,
|
||||||
|
XAxis,
|
||||||
|
YAxis,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
ResponsiveContainer,
|
||||||
|
Area,
|
||||||
|
AreaChart,
|
||||||
|
CartesianGrid,
|
||||||
|
defs,
|
||||||
|
linearGradient,
|
||||||
|
stop
|
||||||
|
} from 'recharts';
|
||||||
|
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||||
|
|
||||||
|
const data = [
|
||||||
|
{ month: 'Jan', revenue: 4000, sales: 2400 },
|
||||||
|
{ month: 'Feb', revenue: 3000, sales: 1398 },
|
||||||
|
{ month: 'Mar', revenue: 2000, sales: 9800 },
|
||||||
|
{ month: 'Apr', revenue: 2780, sales: 3908 },
|
||||||
|
{ month: 'May', revenue: 1890, sales: 4800 },
|
||||||
|
{ month: 'Jun', revenue: 2390, sales: 3800 },
|
||||||
|
{ month: 'Jul', revenue: 3490, sales: 4300 },
|
||||||
|
{ month: 'Aug', revenue: 5000, sales: 4000 },
|
||||||
|
{ month: 'Sep', revenue: 4700, sales: 4200 },
|
||||||
|
{ month: 'Oct', revenue: 5200, sales: 4600 },
|
||||||
|
{ month: 'Nov', revenue: 4800, sales: 4400 },
|
||||||
|
{ month: 'Dec', revenue: 5300, sales: 4800 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const formatCurrency = (value) => {
|
||||||
|
if (value >= 1000000) {
|
||||||
|
return `$${(value / 1000000).toFixed(1)}M`;
|
||||||
|
} else if (value >= 1000) {
|
||||||
|
return `$${(value / 1000).toFixed(1)}K`;
|
||||||
|
}
|
||||||
|
return `$${value}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const StatisticsCard = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
const isTablet = useMediaQuery(theme.breakpoints.between('sm', 'md'));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ width: '100%' }}>
|
||||||
|
<Paper sx={{
|
||||||
|
p: { xs: 1.5, sm: 2 },
|
||||||
|
mb: { xs: 2, sm: 3 },
|
||||||
|
boxShadow: '0px 4px 5px rgba(0, 0, 0, 0.1)',
|
||||||
|
position: 'relative',
|
||||||
|
borderRadius: 2 ,
|
||||||
|
|
||||||
|
}}>
|
||||||
|
<IconButton
|
||||||
|
aria-label="more-actions"
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: { xs: 4, sm: 8 },
|
||||||
|
right: { xs: 4, sm: 8 },
|
||||||
|
color: '#667085'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MoreVertIcon fontSize={isMobile ? 'small' : 'medium'} />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
mb: { xs: 1, sm: 2 },
|
||||||
|
pr: { xs: 3, sm: 4 }
|
||||||
|
}}>
|
||||||
|
<Typography variant="h6" sx={{
|
||||||
|
fontSize: { xs: '15px', sm: '18px' },
|
||||||
|
fontWeight: 500
|
||||||
|
}}>
|
||||||
|
Statistics
|
||||||
|
</Typography>
|
||||||
|
<Typography sx={{
|
||||||
|
fontSize: { xs: '11px', sm: '14px' },
|
||||||
|
fontWeight: 500,
|
||||||
|
color: '#667085'
|
||||||
|
}}>
|
||||||
|
Delivery Times
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<ResponsiveContainer width="100%" height={isMobile ? 250 : isTablet ? 290 : 295}>
|
||||||
|
<AreaChart data={data} margin={{
|
||||||
|
top: isMobile ? -30 : -45,
|
||||||
|
right: isMobile ? 15 : 30,
|
||||||
|
left: isMobile ? 10 : 20,
|
||||||
|
bottom: isMobile ? 10 : 20
|
||||||
|
}}>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="colorRevenue" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0%" stopColor={theme.palette.primary.main} stopOpacity={0.8} />
|
||||||
|
<stop offset="100%" stopColor={theme.palette.primary.main} stopOpacity={0} />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="colorSales" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0%" stopColor="#81C2FF" stopOpacity={0.8} />
|
||||||
|
<stop offset="100%" stopColor="#81C2FF" stopOpacity={0} />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<CartesianGrid stroke="#eee" strokeDasharray="0 0" vertical={false} />
|
||||||
|
<XAxis
|
||||||
|
dataKey="month"
|
||||||
|
axisLine={false}
|
||||||
|
tickLine={false}
|
||||||
|
tickMargin={isMobile ? 8 : 15}
|
||||||
|
tick={{ fontSize: isMobile ? 11 : 12 }}
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
tickFormatter={formatCurrency}
|
||||||
|
axisLine={false}
|
||||||
|
tickLine={false}
|
||||||
|
tickMargin={isMobile ? 8 : 15}
|
||||||
|
tick={{ fontSize: isMobile ? 11 : 12 }}
|
||||||
|
/>
|
||||||
|
<Tooltip />
|
||||||
|
<Legend
|
||||||
|
verticalAlign="top"
|
||||||
|
height={isMobile ? 30 : 36}
|
||||||
|
iconType="circle"
|
||||||
|
iconSize={isMobile ? 8 : 10}
|
||||||
|
wrapperStyle={{
|
||||||
|
paddingBottom: isMobile ? '15px' : '20px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Area
|
||||||
|
name="Revenue"
|
||||||
|
type="monotone"
|
||||||
|
dataKey="revenue"
|
||||||
|
stroke='#E46A11'
|
||||||
|
strokeWidth={isMobile ? 2 : 3}
|
||||||
|
fill="url(#colorRevenue)"
|
||||||
|
/>
|
||||||
|
<Area
|
||||||
|
type="monotone"
|
||||||
|
name="Sales"
|
||||||
|
dataKey="sales"
|
||||||
|
stroke="#0182FC"
|
||||||
|
strokeWidth={isMobile ? 2 : 3}
|
||||||
|
fill="url(#colorSales)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Line
|
||||||
|
type="monotone"
|
||||||
|
dataKey="revenue"
|
||||||
|
stroke={theme.palette.primary.main}
|
||||||
|
strokeWidth={isMobile ? 2 : 3}
|
||||||
|
dot={{
|
||||||
|
r: isMobile ? 4 : 6,
|
||||||
|
fill: theme.palette.primary.main,
|
||||||
|
stroke: '#fff',
|
||||||
|
strokeWidth: 2
|
||||||
|
}}
|
||||||
|
activeDot={{
|
||||||
|
r: isMobile ? 6 : 8,
|
||||||
|
fill: theme.palette.primary.main,
|
||||||
|
stroke: '#fff',
|
||||||
|
strokeWidth: 2
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Line
|
||||||
|
type="monotone"
|
||||||
|
dataKey="sales"
|
||||||
|
stroke="#0182FC"
|
||||||
|
strokeWidth={isMobile ? 2 : 3}
|
||||||
|
dot={{
|
||||||
|
r: isMobile ? 4 : 6,
|
||||||
|
fill: "#0182FC",
|
||||||
|
stroke: '#fff',
|
||||||
|
strokeWidth: 2
|
||||||
|
}}
|
||||||
|
activeDot={{
|
||||||
|
r: isMobile ? 6 : 8,
|
||||||
|
fill: "#0182FC",
|
||||||
|
stroke: '#fff',
|
||||||
|
strokeWidth: 2
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</AreaChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StatisticsCard;
|
||||||