init
commit
4f62ca2f21
@ -0,0 +1,58 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": ["airbnb", "prettier", "plugin:react/jsx-runtime", "plugin:jsx-a11y/recommended", "plugin:react-hooks/recommended"],
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"node": {
|
||||
"moduleDirectory": ["node_modules", "src/"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"parser": "@babel/eslint-parser",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true,
|
||||
"impliedStrict": true
|
||||
},
|
||||
"ecmaVersion": 12
|
||||
},
|
||||
"plugins": ["prettier", "react", "react-hooks"],
|
||||
"rules": {
|
||||
"react/jsx-filename-extension": 0,
|
||||
"no-param-reassign": 0,
|
||||
"react/prop-types": 1,
|
||||
"react/require-default-props": 0,
|
||||
"react/no-array-index-key": 0,
|
||||
"react/jsx-props-no-spreading": 0,
|
||||
"react/forbid-prop-types": 0,
|
||||
"import/order": 0,
|
||||
"import/no-cycle": 0,
|
||||
"no-console": 0,
|
||||
"jsx-a11y/anchor-is-valid": 0,
|
||||
"prefer-destructuring": 0,
|
||||
"no-shadow": 0,
|
||||
"import/no-named-as-default": 0,
|
||||
"no-unused-vars": [
|
||||
1,
|
||||
{
|
||||
"ignoreRestSiblings": false
|
||||
}
|
||||
],
|
||||
"prettier/prettier": [
|
||||
2,
|
||||
{
|
||||
"bracketSpacing": true,
|
||||
"printWidth": 140,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
/.idea/
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"bracketSpacing": true,
|
||||
"printWidth": 140,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"useTabs": false
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
# Introduction
|
||||
|
||||
This is material design template created based on materially structure
|
||||
|
||||
# Getting Started
|
||||
|
||||
1. Installation process
|
||||
- run 'npm install / yarn'
|
||||
- start dev server run 'npm run start / yarn start'
|
||||
2. Deployment process
|
||||
- Goto full-version directory and open package.json. Update homepage URL to the production URL
|
||||
- Goto full-version directory and run 'npm run build / yarn build'
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "commonjs",
|
||||
"baseUrl": "src"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,131 @@
|
||||
{
|
||||
"name": "berry-material-react",
|
||||
"version": "3.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@auth0/auth0-spa-js": "^1.19.4",
|
||||
"@emotion/cache": "^11.7.1",
|
||||
"@emotion/react": "^11.7.1",
|
||||
"@emotion/styled": "^11.6.0",
|
||||
"@fullcalendar/daygrid": "^5.10.1",
|
||||
"@fullcalendar/interaction": "^5.10.1",
|
||||
"@fullcalendar/list": "^5.10.1",
|
||||
"@fullcalendar/react": "^5.10.1",
|
||||
"@fullcalendar/timegrid": "^5.10.1",
|
||||
"@fullcalendar/timeline": "^5.10.1",
|
||||
"@hookform/resolvers": "^2.8.8",
|
||||
"@mui/icons-material": "^5.4.1",
|
||||
"@mui/lab": "^5.0.0-alpha.68",
|
||||
"@mui/material": "^5.4.1",
|
||||
"@mui/styles": "^5.4.1",
|
||||
"@mui/system": "^5.4.1",
|
||||
"@mui/utils": "^5.4.1",
|
||||
"@mui/x-data-grid": "^5.5.0",
|
||||
"@reduxjs/toolkit": "^1.7.2",
|
||||
"@tabler/icons": "^1.53.0",
|
||||
"amazon-cognito-identity-js": "^5.2.6",
|
||||
"apexcharts": "^3.33.1",
|
||||
"axios": "^0.25.0",
|
||||
"axios-mock-adapter": "^1.20.0",
|
||||
"chance": "^1.1.8",
|
||||
"csstype": "^3.0.10",
|
||||
"date-fns": "^2.28.0",
|
||||
"draft-js": "^0.11.7",
|
||||
"emoji-picker-react": "^3.5.1",
|
||||
"firebase": "^9.6.6",
|
||||
"formik": "^2.2.9",
|
||||
"framer-motion": "^4.1.13",
|
||||
"history": "^5.2.0",
|
||||
"image-to-base64": "^2.2.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"lodash": "^4.17.21",
|
||||
"material-ui-popup-state": "^2.0.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^17.0.2",
|
||||
"react-apexcharts": "^1.3.9",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-copy-to-clipboard": "^5.0.4",
|
||||
"react-currency-format": "^1.1.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-draft-wysiwyg": "^1.14.7",
|
||||
"react-draggable": "^4.4.4",
|
||||
"react-dropzone": "^12.0.2",
|
||||
"react-google-recaptcha": "^2.1.0",
|
||||
"react-hook-form": "^7.26.1",
|
||||
"react-images": "^1.2.0-beta.7",
|
||||
"react-intersection-observer": "^8.33.1",
|
||||
"react-intl": "^5.24.6",
|
||||
"react-markdown": "^8.0.0",
|
||||
"react-number-format": "^4.9.1",
|
||||
"react-organizational-chart": "^2.1.1",
|
||||
"react-otp-input-rc-17": "^2.4.1-minor",
|
||||
"react-perfect-scrollbar": "^1.5.8",
|
||||
"react-quill": "^2.0.0-beta.4",
|
||||
"react-redux": "^7.2.6",
|
||||
"react-router-dom": "^6.2.1",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-slick": "^0.28.1",
|
||||
"react-syntax-highlighter": "^15.4.5",
|
||||
"react-timer-hook": "^3.0.5",
|
||||
"react-to-print": "^2.14.4",
|
||||
"react-window": "^1.8.6",
|
||||
"redux": "^4.1.2",
|
||||
"redux-persist": "^6.0.0",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"slick-carousel": "^1.8.1",
|
||||
"stylis-plugin-rtl": "^2.1.1",
|
||||
"typescript": "^4.5.5",
|
||||
"uuid": "^8.3.2",
|
||||
"web-vitals": "^2.1.4",
|
||||
"yup": "^0.32.11"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"@babel/preset-react"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.2",
|
||||
"@babel/eslint-parser": "^7.15.8",
|
||||
"eslint": "^7.27.0",
|
||||
"eslint-config-airbnb-typescript": "^12.3.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-config-react-app": "6.0.0",
|
||||
"eslint-import-resolver-typescript": "^2.5.0",
|
||||
"eslint-plugin-flowtype": "^5.7.2",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"prettier": "^2.5.1",
|
||||
"react-error-overlay": "6.0.9",
|
||||
"sass": "^1.49.7"
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<svg width="46" height="55" viewBox="0 0 46 55" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clipPath="url(#clip0)">
|
||||
<path d="M19.6667 55C8.82205 55 0 46.2504 0 35.4968C0 24.7431 8.82292 15.9935 19.6667 15.9935C30.5105 15.9935 39.3334 24.7431 39.3334 35.4968C39.3334 46.2504 30.5122 55 19.6667 55ZM19.6667 17.8563C9.8587 17.8563 1.87839 25.7686 1.87839 35.4959C1.87839 45.2233 9.8587 53.1355 19.6667 53.1355C29.4747 53.1355 37.4559 45.2215 37.4559 35.4942C37.4559 25.7668 29.4765 17.8563 19.6667 17.8563Z" fill="#2196F3"/>
|
||||
<path d="M33.9387 36.3618C33.3269 34.1133 27.7188 33.8706 24.3807 34.6949C22.6326 35.1283 20.846 35.6917 19.0034 36.0159C20.3521 37.2026 21.8005 38.3251 23.879 38.6042C29.0361 39.2942 32.2404 37.6898 33.9387 36.3618Z" fill="#2196F3"/>
|
||||
<path d="M23.8788 38.6042C21.7959 38.3251 20.3519 37.2026 19.0032 36.016C16.9159 34.1792 15.0594 32.189 11.4154 32.9379C5.62198 34.1289 4.85978 40.9247 9.3333 45.2917C11.254 47.2864 13.7197 48.6822 16.4284 49.3079C19.137 49.9336 21.9709 49.7621 24.5828 48.8144C27.1946 47.8667 29.4709 46.1839 31.1327 43.9724C32.7945 41.7608 33.7696 39.1165 33.9385 36.3635C32.2402 37.6898 29.0358 39.2942 23.8788 38.6042Z" fill="#673AB7"/>
|
||||
<path d="M26.9105 23.8962C26.1876 25.4331 32.6321 27.1381 33.4031 32.2419C33.7746 27.2178 27.8046 21.9962 26.9105 23.8962Z" fill="#2196F3"/>
|
||||
<path d="M13.3649 30.3107C14.5267 29.8335 15.0784 28.5126 14.5972 27.3604C14.116 26.2083 12.784 25.6611 11.6222 26.1384C10.4604 26.6156 9.90867 27.9365 10.3899 29.0887C10.8712 30.2408 12.2031 30.7879 13.3649 30.3107Z" fill="#673AB7"/>
|
||||
<path d="M18.5351 24.1103C19.0786 23.5714 19.0786 22.6977 18.5351 22.1587C17.9917 21.6198 17.1106 21.6198 16.5672 22.1587C16.0238 22.6977 16.0238 23.5714 16.5672 24.1103C17.1106 24.6492 17.9917 24.6492 18.5351 24.1103Z" fill="#2196F3"/>
|
||||
<path d="M23.4513 15.2376C25.4617 9.3485 24.1103 4.64345 19.9786 2.40881C17.1544 2.97831 15.4779 4.334 14.5444 6.20544C20.0843 5.76077 23.5999 9.1994 23.4513 15.2376Z" fill="#2196F3"/>
|
||||
<path d="M46.0001 10.0923C36.0487 6.55051 29.7685 7.76491 28.7808 15.8349C34.4841 21.6703 40.2286 18.8774 46.0001 10.0923Z" fill="#2196F3"/>
|
||||
<path d="M38.0851 6.89635C38.5466 4.94082 38.7861 2.6299 38.8219 0C28.5017 2.27885 23.8473 6.6337 27.3584 13.9782C27.5333 14.0198 27.7011 14.0536 27.8698 14.0883C28.6905 8.34132 32.3031 6.2133 38.0851 6.89635Z" fill="#2196F3"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="46" height="55" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
@ -0,0 +1,100 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Berry - React Material Admin Dashboard Template</title>
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.svg" />
|
||||
<!-- Meta Tags-->
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#2296f3" />
|
||||
<meta name="title" content="Berry - React Material Admin Dashboard Template by CodedThemes" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Start your next React project with Berry admin template. It build with Reactjs, Material-UI, Redux, and Hook for faster web development."
|
||||
/>
|
||||
<meta
|
||||
name="keywords"
|
||||
content="react admin template, material-ui react dashboard template, reactjs admin template, reactjs dashboard, react backend template"
|
||||
/>
|
||||
<meta name="author" content="CodedThemes" />
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://berrydashboard.io/" />
|
||||
<meta property="og:site_name" content="berrydashboard.io" />
|
||||
<meta property="article:publisher" content="https://www.facebook.com/codedthemes" />
|
||||
<meta property="og:title" content="Berry - React Material Dashboard Template" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Berry Dashboard is made for the faster web application development built using Material-UI, Reactjs, Redux & Hook API."
|
||||
/>
|
||||
<meta property="og:image" content="https://berrydashboard.io/og-image/og-facebook.png" />
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content="https://berrydashboard.io" />
|
||||
<meta property="twitter:title" content="Berry - React Material Dashboard Template" />
|
||||
<meta
|
||||
property="twitter:description"
|
||||
content="Berry Dashboard is made for the faster web application development built using Material-UI, Reactjs, Redux & Hook API."
|
||||
/>
|
||||
<meta property="twitter:image" content="https://berrydashboard.io/og-image/og-twitter.png" />
|
||||
<meta name="twitter:creator" content="@codedthemes" />
|
||||
<!--
|
||||
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
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap"
|
||||
rel="stylesheet"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<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`.
|
||||
-->
|
||||
|
||||
<script type="text/javascript">
|
||||
(function (c, l, a, r, i, t, y) {
|
||||
c[a] =
|
||||
c[a] ||
|
||||
function () {
|
||||
(c[a].q = c[a].q || []).push(arguments);
|
||||
};
|
||||
t = l.createElement(r);
|
||||
t.async = 1;
|
||||
t.src = 'https://www.clarity.ms/tag/' + i;git
|
||||
y = l.getElementsByTagName(r)[0];
|
||||
y.parentNode.insertBefore(t, y);
|
||||
})(window, document, 'clarity', 'script', '6sbb1vpcjo');
|
||||
</script>
|
||||
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-X1LG1CJ1GG"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-X1LG1CJ1GG');
|
||||
gtag('event', 'action', { non_interaction: true });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,37 @@
|
||||
// routing
|
||||
import Routes from 'routes';
|
||||
|
||||
// project imports
|
||||
import Locales from 'ui-component/Locales';
|
||||
import NavigationScroll from 'layout/NavigationScroll';
|
||||
import RTLLayout from 'ui-component/RTLLayout';
|
||||
import Snackbar from 'ui-component/extended/Snackbar';
|
||||
import ThemeCustomization from 'themes';
|
||||
|
||||
// auth provider
|
||||
import { FirebaseProvider as AuthProvider } from 'contexts/FirebaseContext';
|
||||
// import { AWSCognitoProvider as AuthProvider } from 'contexts/AWSCognitoContext';
|
||||
// import { JWTProvider as AuthProvider } from 'contexts/JWTContext';
|
||||
// import { Auth0Provider as AuthProvider } from 'contexts/Auth0Context';
|
||||
|
||||
// ==============================|| APP ||============================== //
|
||||
|
||||
const App = () => (
|
||||
<ThemeCustomization>
|
||||
{/* RTL layout */}
|
||||
<RTLLayout>
|
||||
<Locales>
|
||||
<NavigationScroll>
|
||||
<AuthProvider>
|
||||
<>
|
||||
<Routes />
|
||||
<Snackbar />
|
||||
</>
|
||||
</AuthProvider>
|
||||
</NavigationScroll>
|
||||
</Locales>
|
||||
</RTLLayout>
|
||||
</ThemeCustomization>
|
||||
);
|
||||
|
||||
export default App;
|
@ -0,0 +1,6 @@
|
||||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.06129 13.2253L4.31871 15.9975L1.60458 16.0549C0.793457 14.5504 0.333374 12.8292 0.333374 11C0.333374 9.23119 0.763541 7.56319 1.52604 6.09448H1.52662L3.94296 6.53748L5.00146 8.93932C4.77992 9.58519 4.65917 10.2785 4.65917 11C4.65925 11.783 4.80108 12.5332 5.06129 13.2253Z" fill="#FBBB00"/>
|
||||
<path d="M21.4804 9.00732C21.6029 9.65257 21.6668 10.3189 21.6668 11C21.6668 11.7637 21.5865 12.5086 21.4335 13.2271C20.9143 15.6722 19.5575 17.8073 17.678 19.3182L17.6774 19.3177L14.6339 19.1624L14.2031 16.4734C15.4503 15.742 16.425 14.5974 16.9384 13.2271H11.2346V9.00732H17.0216H21.4804Z" fill="#518EF8"/>
|
||||
<path d="M17.6772 19.3176L17.6777 19.3182C15.8498 20.7875 13.5277 21.6666 11 21.6666C6.93783 21.6666 3.40612 19.3962 1.60449 16.0549L5.0612 13.2253C5.96199 15.6294 8.28112 17.3408 11 17.3408C12.1686 17.3408 13.2634 17.0249 14.2029 16.4734L17.6772 19.3176Z" fill="#28B446"/>
|
||||
<path d="M17.8085 2.78892L14.353 5.61792C13.3807 5.01017 12.2313 4.65908 11 4.65908C8.21963 4.65908 5.85713 6.44896 5.00146 8.93925L1.52658 6.09442H1.526C3.30125 2.67171 6.8775 0.333252 11 0.333252C13.5881 0.333252 15.9612 1.25517 17.8085 2.78892Z" fill="#F14336"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 250 KiB |
@ -0,0 +1,157 @@
|
||||
// paper & background
|
||||
$paper: #ffffff;
|
||||
|
||||
// primary
|
||||
$primaryLight: #eceff1;
|
||||
$primaryMain: #607d8b;
|
||||
$primaryDark: #546e7a;
|
||||
$primary200: #b0bec5;
|
||||
$primary800: #455a64;
|
||||
|
||||
// secondary
|
||||
$secondaryLight: #e0f2f1;
|
||||
$secondaryMain: #009688;
|
||||
$secondaryDark: #00897b;
|
||||
$secondary200: #80cbc4;
|
||||
$secondary800: #00695c;
|
||||
|
||||
// success Colors
|
||||
$successLight: #edf7ed;
|
||||
$success200: #b6e0b3;
|
||||
$successMain: #6cc067;
|
||||
$successDark: #64ba5f;
|
||||
|
||||
// error
|
||||
$errorLight: #e48784;
|
||||
$errorMain: #d9534f;
|
||||
$errorDark: #d54c48;
|
||||
|
||||
// orange
|
||||
$orangeLight: #fbe9e7;
|
||||
$orangeMain: #ffab91;
|
||||
$orangeDark: #d84315;
|
||||
|
||||
// warning
|
||||
$warningLight: #fdf5ea;
|
||||
$warningMain: #f0ad4e;
|
||||
$warningDark: #ec9c3d;
|
||||
|
||||
// grey
|
||||
$grey50: #fafafa;
|
||||
$grey100: #f5f5f5;
|
||||
$grey200: #eeeeee;
|
||||
$grey300: #e0e0e0;
|
||||
$grey500: #9e9e9e;
|
||||
$grey600: #757575;
|
||||
$grey700: #616161;
|
||||
$grey900: #212121;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
$darkBackground: #0e1b23; // level 3
|
||||
$darkPaper: #060d12; // level 4
|
||||
|
||||
// dark 800 & 900
|
||||
$darkLevel1: #0b161d; // level 1
|
||||
$darkLevel2: #14252f; // level 2
|
||||
|
||||
// primary dark
|
||||
$darkPrimaryLight: #eceff1;
|
||||
$darkPrimaryMain: #78919c;
|
||||
$darkPrimaryDark: #587583;
|
||||
$darkPrimary200: #b0bec5;
|
||||
$darkPrimary800: #44606e;
|
||||
|
||||
// secondary dark
|
||||
$darkSecondaryLight: #e0f2f1;
|
||||
$darkSecondaryMain: #009688;
|
||||
$darkSecondaryDark: #00897b;
|
||||
$darkSecondary200: #80cbc4;
|
||||
$darkSecondary800: #00695c;
|
||||
|
||||
// text variants
|
||||
$darkTextTitle: #e4e8f7;
|
||||
$darkTextPrimary: #d5d9e9;
|
||||
$darkTextSecondary: #d8ddf0;
|
||||
|
||||
// ==============================|| JAVASCRIPT ||============================== //
|
||||
|
||||
:export {
|
||||
// paper & background
|
||||
paper: $paper;
|
||||
|
||||
// primary
|
||||
primaryLight: $primaryLight;
|
||||
primary200: $primary200;
|
||||
primaryMain: $primaryMain;
|
||||
primaryDark: $primaryDark;
|
||||
primary800: $primary800;
|
||||
|
||||
// secondary
|
||||
secondaryLight: $secondaryLight;
|
||||
secondary200: $secondary200;
|
||||
secondaryMain: $secondaryMain;
|
||||
secondaryDark: $secondaryDark;
|
||||
secondary800: $secondary800;
|
||||
|
||||
// success
|
||||
successLight: $successLight;
|
||||
success200: $success200;
|
||||
successMain: $successMain;
|
||||
successDark: $successDark;
|
||||
|
||||
// error
|
||||
errorLight: $errorLight;
|
||||
errorMain: $errorMain;
|
||||
errorDark: $errorDark;
|
||||
|
||||
// orange
|
||||
orangeLight: $orangeLight;
|
||||
orangeMain: $orangeMain;
|
||||
orangeDark: $orangeDark;
|
||||
|
||||
// warning
|
||||
warningLight: $warningLight;
|
||||
warningMain: $warningMain;
|
||||
warningDark: $warningDark;
|
||||
|
||||
// grey
|
||||
grey50: $grey50;
|
||||
grey100: $grey100;
|
||||
grey200: $grey200;
|
||||
grey300: $grey300;
|
||||
grey500: $grey500;
|
||||
grey600: $grey600;
|
||||
grey700: $grey700;
|
||||
grey900: $grey900;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
darkPaper: $darkPaper;
|
||||
darkBackground: $darkBackground;
|
||||
|
||||
// dark 800 & 900
|
||||
darkLevel1: $darkLevel1;
|
||||
darkLevel2: $darkLevel2;
|
||||
|
||||
// text variants
|
||||
darkTextTitle: $darkTextTitle;
|
||||
darkTextPrimary: $darkTextPrimary;
|
||||
darkTextSecondary: $darkTextSecondary;
|
||||
|
||||
// primary dark
|
||||
darkPrimaryLight: $darkPrimaryLight;
|
||||
darkPrimaryMain: $darkPrimaryMain;
|
||||
darkPrimaryDark: $darkPrimaryDark;
|
||||
darkPrimary200: $darkPrimary200;
|
||||
darkPrimary800: $darkPrimary800;
|
||||
|
||||
// secondary dark
|
||||
darkSecondaryLight: $darkSecondaryLight;
|
||||
darkSecondaryMain: $darkSecondaryMain;
|
||||
darkSecondaryDark: $darkSecondaryDark;
|
||||
darkSecondary200: $darkSecondary200;
|
||||
darkSecondary800: $darkSecondary800;
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
// paper & background
|
||||
$paper: #ffffff;
|
||||
|
||||
// primary
|
||||
$primaryLight: #e4e7ec;
|
||||
$primaryMain: #203461;
|
||||
$primaryDark: #1c2f59;
|
||||
$primary200: #909ab0;
|
||||
$primary800: #132145;
|
||||
|
||||
// secondary
|
||||
$secondaryLight: #fde8ef;
|
||||
$secondaryMain: #ec407a;
|
||||
$secondaryDark: #ea3a72;
|
||||
$secondary200: #f6a0bd;
|
||||
$secondary800: #e42a5d;
|
||||
|
||||
// success Colors
|
||||
$successLight: #e3f8e8;
|
||||
$success200: #8be09f;
|
||||
$successMain: #17c13e;
|
||||
$successDark: #14bb38;
|
||||
|
||||
// error
|
||||
$errorLight: #e48784;
|
||||
$errorMain: #d9534f;
|
||||
$errorDark: #d54c48;
|
||||
|
||||
// orange
|
||||
$orangeLight: #fbe9e7;
|
||||
$orangeMain: #ffab91;
|
||||
$orangeDark: #d84315;
|
||||
|
||||
// warning
|
||||
$warningLight: #fdf5ea;
|
||||
$warningMain: #f0ad4e;
|
||||
$warningDark: #ec9c3d;
|
||||
|
||||
// grey
|
||||
$grey50: #fafafa;
|
||||
$grey100: #f5f5f5;
|
||||
$grey200: #eeeeee;
|
||||
$grey300: #e0e0e0;
|
||||
$grey500: #9e9e9e;
|
||||
$grey600: #757575;
|
||||
$grey700: #616161;
|
||||
$grey900: #212121;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
$darkBackground: #0a0f23; // level 3
|
||||
$darkPaper: #030614; // level 4
|
||||
|
||||
// dark 800 & 900
|
||||
$darkLevel1: #070e13; // level 1
|
||||
$darkLevel2: #12172f; // level 2
|
||||
|
||||
// primary dark
|
||||
$darkPrimaryLight: #ecedf1;
|
||||
$darkPrimaryMain: #606d88;
|
||||
$darkPrimaryDark: #586580;
|
||||
$darkPrimary200: #b0b6c4;
|
||||
$darkPrimary800: #44506b;
|
||||
|
||||
// secondary dark
|
||||
$darkSecondaryLight: #fde8ef;
|
||||
$darkSecondaryMain: #ec407a;
|
||||
$darkSecondaryDark: #ea3a72;
|
||||
$darkSecondary200: #f6a0bd;
|
||||
$darkSecondary800: #e42a5d;
|
||||
|
||||
// text variants
|
||||
$darkTextTitle: #e4e8f7;
|
||||
$darkTextPrimary: #d5d9e9;
|
||||
$darkTextSecondary: #d8ddf0;
|
||||
|
||||
// ==============================|| JAVASCRIPT ||============================== //
|
||||
|
||||
:export {
|
||||
// paper & background
|
||||
paper: $paper;
|
||||
|
||||
// primary
|
||||
primaryLight: $primaryLight;
|
||||
primary200: $primary200;
|
||||
primaryMain: $primaryMain;
|
||||
primaryDark: $primaryDark;
|
||||
primary800: $primary800;
|
||||
|
||||
// secondary
|
||||
secondaryLight: $secondaryLight;
|
||||
secondary200: $secondary200;
|
||||
secondaryMain: $secondaryMain;
|
||||
secondaryDark: $secondaryDark;
|
||||
secondary800: $secondary800;
|
||||
|
||||
// success
|
||||
successLight: $successLight;
|
||||
success200: $success200;
|
||||
successMain: $successMain;
|
||||
successDark: $successDark;
|
||||
|
||||
// error
|
||||
errorLight: $errorLight;
|
||||
errorMain: $errorMain;
|
||||
errorDark: $errorDark;
|
||||
|
||||
// orange
|
||||
orangeLight: $orangeLight;
|
||||
orangeMain: $orangeMain;
|
||||
orangeDark: $orangeDark;
|
||||
|
||||
// warning
|
||||
warningLight: $warningLight;
|
||||
warningMain: $warningMain;
|
||||
warningDark: $warningDark;
|
||||
|
||||
// grey
|
||||
grey50: $grey50;
|
||||
grey100: $grey100;
|
||||
grey200: $grey200;
|
||||
grey300: $grey300;
|
||||
grey500: $grey500;
|
||||
grey600: $grey600;
|
||||
grey700: $grey700;
|
||||
grey900: $grey900;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
darkPaper: $darkPaper;
|
||||
darkBackground: $darkBackground;
|
||||
|
||||
// dark 800 & 900
|
||||
darkLevel1: $darkLevel1;
|
||||
darkLevel2: $darkLevel2;
|
||||
|
||||
// text variants
|
||||
darkTextTitle: $darkTextTitle;
|
||||
darkTextPrimary: $darkTextPrimary;
|
||||
darkTextSecondary: $darkTextSecondary;
|
||||
|
||||
// primary dark
|
||||
darkPrimaryLight: $darkPrimaryLight;
|
||||
darkPrimaryMain: $darkPrimaryMain;
|
||||
darkPrimaryDark: $darkPrimaryDark;
|
||||
darkPrimary200: $darkPrimary200;
|
||||
darkPrimary800: $darkPrimary800;
|
||||
|
||||
// secondary dark
|
||||
darkSecondaryLight: $darkSecondaryLight;
|
||||
darkSecondaryMain: $darkSecondaryMain;
|
||||
darkSecondaryDark: $darkSecondaryDark;
|
||||
darkSecondary200: $darkSecondary200;
|
||||
darkSecondary800: $darkSecondary800;
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
// paper & background
|
||||
$paper: #ffffff;
|
||||
|
||||
// primary
|
||||
$primaryLight: #e3ebeb;
|
||||
$primaryMain: #16595a;
|
||||
$primaryDark: #135152;
|
||||
$primary200: #8bacad;
|
||||
$primary800: #0c3e3f;
|
||||
|
||||
// secondary
|
||||
$secondaryLight: #f8f0e5;
|
||||
$secondaryMain: #c77e23;
|
||||
$secondaryDark: #c1761f;
|
||||
$secondary200: #e3bf91;
|
||||
$secondary800: #b36115;
|
||||
|
||||
// success Colors
|
||||
$successLight: #b9f6ca;
|
||||
$success200: #69f0ae;
|
||||
$successMain: #00e676;
|
||||
$successDark: #00c853;
|
||||
|
||||
// error
|
||||
$errorLight: #ef9a9a;
|
||||
$errorMain: #f44336;
|
||||
$errorDark: #c62828;
|
||||
|
||||
// orange
|
||||
$orangeLight: #fbe9e7;
|
||||
$orangeMain: #ffab91;
|
||||
$orangeDark: #d84315;
|
||||
|
||||
// warning
|
||||
$warningLight: #fff8e1;
|
||||
$warningMain: #ffe57f;
|
||||
$warningDark: #ffc107;
|
||||
|
||||
// grey
|
||||
$grey50: #fafafa;
|
||||
$grey100: #f5f5f5;
|
||||
$grey200: #eeeeee;
|
||||
$grey300: #e0e0e0;
|
||||
$grey500: #9e9e9e;
|
||||
$grey600: #757575;
|
||||
$grey700: #616161;
|
||||
$grey900: #212121;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
$darkBackground: #010606; // level 3
|
||||
$darkPaper: #010f17; // level 4
|
||||
|
||||
// dark 800 & 900
|
||||
$darkLevel1: #02131d; // level 1
|
||||
$darkLevel2: #010f17; // level 2
|
||||
|
||||
// primary dark
|
||||
$darkPrimaryLight: #eceff1;
|
||||
$darkPrimaryMain: #1f7778;
|
||||
$darkPrimaryDark: #1b6f70;
|
||||
$darkPrimary200: #8fbbbc;
|
||||
$darkPrimary800: #125a5b;
|
||||
|
||||
// secondary dark
|
||||
$darkSecondaryLight: #f8f0e5;
|
||||
$darkSecondaryMain: #c77e23;
|
||||
$darkSecondaryDark: #c1761f;
|
||||
$darkSecondary200: #e3bf91;
|
||||
$darkSecondary800: #b36115;
|
||||
|
||||
// text variants
|
||||
$darkTextTitle: #ffffff;
|
||||
$darkTextPrimary: #ffffff;
|
||||
$darkTextSecondary: #8492c4;
|
||||
|
||||
// ==============================|| JAVASCRIPT ||============================== //
|
||||
|
||||
:export {
|
||||
// paper & background
|
||||
paper: $paper;
|
||||
|
||||
// primary
|
||||
primaryLight: $primaryLight;
|
||||
primary200: $primary200;
|
||||
primaryMain: $primaryMain;
|
||||
primaryDark: $primaryDark;
|
||||
primary800: $primary800;
|
||||
|
||||
// secondary
|
||||
secondaryLight: $secondaryLight;
|
||||
secondary200: $secondary200;
|
||||
secondaryMain: $secondaryMain;
|
||||
secondaryDark: $secondaryDark;
|
||||
secondary800: $secondary800;
|
||||
|
||||
// success
|
||||
successLight: $successLight;
|
||||
success200: $success200;
|
||||
successMain: $successMain;
|
||||
successDark: $successDark;
|
||||
|
||||
// error
|
||||
errorLight: $errorLight;
|
||||
errorMain: $errorMain;
|
||||
errorDark: $errorDark;
|
||||
|
||||
// orange
|
||||
orangeLight: $orangeLight;
|
||||
orangeMain: $orangeMain;
|
||||
orangeDark: $orangeDark;
|
||||
|
||||
// warning
|
||||
warningLight: $warningLight;
|
||||
warningMain: $warningMain;
|
||||
warningDark: $warningDark;
|
||||
|
||||
// grey
|
||||
grey50: $grey50;
|
||||
grey100: $grey100;
|
||||
grey200: $grey200;
|
||||
grey300: $grey300;
|
||||
grey500: $grey500;
|
||||
grey600: $grey600;
|
||||
grey700: $grey700;
|
||||
grey900: $grey900;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
darkPaper: $darkPaper;
|
||||
darkBackground: $darkBackground;
|
||||
|
||||
// dark 800 & 900
|
||||
darkLevel1: $darkLevel1;
|
||||
darkLevel2: $darkLevel2;
|
||||
|
||||
// text variants
|
||||
darkTextTitle: $darkTextTitle;
|
||||
darkTextPrimary: $darkTextPrimary;
|
||||
darkTextSecondary: $darkTextSecondary;
|
||||
|
||||
// primary dark
|
||||
darkPrimaryLight: $darkPrimaryLight;
|
||||
darkPrimaryMain: $darkPrimaryMain;
|
||||
darkPrimaryDark: $darkPrimaryDark;
|
||||
darkPrimary200: $darkPrimary200;
|
||||
darkPrimary800: $darkPrimary800;
|
||||
|
||||
// secondary dark
|
||||
darkSecondaryLight: $darkSecondaryLight;
|
||||
darkSecondaryMain: $darkSecondaryMain;
|
||||
darkSecondaryDark: $darkSecondaryDark;
|
||||
darkSecondary200: $darkSecondary200;
|
||||
darkSecondary800: $darkSecondary800;
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
// paper & background
|
||||
$paper: #ffffff;
|
||||
|
||||
// primary
|
||||
$primaryLight: #e3e8e8;
|
||||
$primaryMain: #173e43;
|
||||
$primaryDark: #14383d;
|
||||
$primary200: #8b9fa1;
|
||||
$primary800: #0d282c;
|
||||
|
||||
// secondary
|
||||
$secondaryLight: #e8f6f5;
|
||||
$secondaryMain: #3fb0ac;
|
||||
$secondaryDark: #39a9a5;
|
||||
$secondary200: #9fd8d6;
|
||||
$secondary800: #299792;
|
||||
|
||||
// success Colors
|
||||
$successLight: #b9f6ca;
|
||||
$success200: #69f0ae;
|
||||
$successMain: #00e676;
|
||||
$successDark: #00c853;
|
||||
|
||||
// error
|
||||
$errorLight: #ef9a9a;
|
||||
$errorMain: #f44336;
|
||||
$errorDark: #c62828;
|
||||
|
||||
// orange
|
||||
$orangeLight: #fbe9e7;
|
||||
$orangeMain: #ffab91;
|
||||
$orangeDark: #d84315;
|
||||
|
||||
// warning
|
||||
$warningLight: #fff8e1;
|
||||
$warningMain: #ffe57f;
|
||||
$warningDark: #ffc107;
|
||||
|
||||
// grey
|
||||
$grey50: #fafafa;
|
||||
$grey100: #f5f5f5;
|
||||
$grey200: #eeeeee;
|
||||
$grey300: #e0e0e0;
|
||||
$grey500: #9e9e9e;
|
||||
$grey600: #757575;
|
||||
$grey700: #616161;
|
||||
$grey900: #212121;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
$darkBackground: #030708; // level 3
|
||||
$darkPaper: #051114; // level 4
|
||||
|
||||
// dark 800 & 900
|
||||
$darkLevel1: #02131d; // level 1
|
||||
$darkLevel2: #051114; // level 2
|
||||
|
||||
// primary dark
|
||||
$darkPrimaryLight: #e3e8e8;
|
||||
$darkPrimaryMain: #3a5b5f;
|
||||
$darkPrimaryDark: #14383d;
|
||||
$darkPrimary200: #8b9fa1;
|
||||
$darkPrimary800: #0d282c;
|
||||
|
||||
// secondary dark
|
||||
$darkSecondaryLight: #e8f6f5;
|
||||
$darkSecondaryMain: #3fb0ac;
|
||||
$darkSecondaryDark: #39a9a5;
|
||||
$darkSecondary200: #9fd8d6;
|
||||
$darkSecondary800: #299792;
|
||||
|
||||
// text variants
|
||||
$darkTextTitle: #ffffff;
|
||||
$darkTextPrimary: #ffffff;
|
||||
$darkTextSecondary: #ccd2eb;
|
||||
|
||||
// ==============================|| JAVASCRIPT ||============================== //
|
||||
|
||||
:export {
|
||||
// paper & background
|
||||
paper: $paper;
|
||||
|
||||
// primary
|
||||
primaryLight: $primaryLight;
|
||||
primary200: $primary200;
|
||||
primaryMain: $primaryMain;
|
||||
primaryDark: $primaryDark;
|
||||
primary800: $primary800;
|
||||
|
||||
// secondary
|
||||
secondaryLight: $secondaryLight;
|
||||
secondary200: $secondary200;
|
||||
secondaryMain: $secondaryMain;
|
||||
secondaryDark: $secondaryDark;
|
||||
secondary800: $secondary800;
|
||||
|
||||
// success
|
||||
successLight: $successLight;
|
||||
success200: $success200;
|
||||
successMain: $successMain;
|
||||
successDark: $successDark;
|
||||
|
||||
// error
|
||||
errorLight: $errorLight;
|
||||
errorMain: $errorMain;
|
||||
errorDark: $errorDark;
|
||||
|
||||
// orange
|
||||
orangeLight: $orangeLight;
|
||||
orangeMain: $orangeMain;
|
||||
orangeDark: $orangeDark;
|
||||
|
||||
// warning
|
||||
warningLight: $warningLight;
|
||||
warningMain: $warningMain;
|
||||
warningDark: $warningDark;
|
||||
|
||||
// grey
|
||||
grey50: $grey50;
|
||||
grey100: $grey100;
|
||||
grey200: $grey200;
|
||||
grey300: $grey300;
|
||||
grey500: $grey500;
|
||||
grey600: $grey600;
|
||||
grey700: $grey700;
|
||||
grey900: $grey900;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
darkPaper: $darkPaper;
|
||||
darkBackground: $darkBackground;
|
||||
|
||||
// dark 800 & 900
|
||||
darkLevel1: $darkLevel1;
|
||||
darkLevel2: $darkLevel2;
|
||||
|
||||
// text variants
|
||||
darkTextTitle: $darkTextTitle;
|
||||
darkTextPrimary: $darkTextPrimary;
|
||||
darkTextSecondary: $darkTextSecondary;
|
||||
|
||||
// primary dark
|
||||
darkPrimaryLight: $darkPrimaryLight;
|
||||
darkPrimaryMain: $darkPrimaryMain;
|
||||
darkPrimaryDark: $darkPrimaryDark;
|
||||
darkPrimary200: $darkPrimary200;
|
||||
darkPrimary800: $darkPrimary800;
|
||||
|
||||
// secondary dark
|
||||
darkSecondaryLight: $darkSecondaryLight;
|
||||
darkSecondaryMain: $darkSecondaryMain;
|
||||
darkSecondaryDark: $darkSecondaryDark;
|
||||
darkSecondary200: $darkSecondary200;
|
||||
darkSecondary800: $darkSecondary800;
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
// paper & background
|
||||
$paper: #ffffff;
|
||||
|
||||
// primary
|
||||
$primaryLight: #e2e5e8;
|
||||
$primaryMain: #0a2342;
|
||||
$primaryDark: #091f3c;
|
||||
$primary200: #8591a1;
|
||||
$primary800: #05152b;
|
||||
|
||||
// secondary
|
||||
$secondaryLight: #e6f4f1;
|
||||
$secondaryMain: #2ca58d;
|
||||
$secondaryDark: #279d85;
|
||||
$secondary200: #96d2c6;
|
||||
$secondary800: #1b8a70;
|
||||
|
||||
// success Colors
|
||||
$successLight: #b9f6ca;
|
||||
$success200: #69f0ae;
|
||||
$successMain: #00e676;
|
||||
$successDark: #00c853;
|
||||
|
||||
// error
|
||||
$errorLight: #ef9a9a;
|
||||
$errorMain: #f44336;
|
||||
$errorDark: #c62828;
|
||||
|
||||
// orange
|
||||
$orangeLight: #fbe9e7;
|
||||
$orangeMain: #ffab91;
|
||||
$orangeDark: #d84315;
|
||||
|
||||
// warning
|
||||
$warningLight: #fff8e1;
|
||||
$warningMain: #ffe57f;
|
||||
$warningDark: #ffc107;
|
||||
|
||||
// grey
|
||||
$grey50: #fafafa;
|
||||
$grey100: #f5f5f5;
|
||||
$grey200: #eeeeee;
|
||||
$grey300: #e0e0e0;
|
||||
$grey500: #9e9e9e;
|
||||
$grey600: #757575;
|
||||
$grey700: #616161;
|
||||
$grey900: #212121;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
$darkBackground: #051327; // level 3
|
||||
$darkPaper: #030c1d; // level 4
|
||||
|
||||
// dark 800 & 900
|
||||
$darkLevel1: #071a33; // level 1
|
||||
$darkLevel2: #091f3c; // level 2
|
||||
|
||||
// primary dark
|
||||
$darkPrimaryLight: #e2e5e8;
|
||||
$darkPrimaryMain: #54657b;
|
||||
$darkPrimaryDark: #2f445e;
|
||||
$darkPrimary200: #8591a1;
|
||||
$darkPrimary800: #05152b;
|
||||
|
||||
// secondary dark
|
||||
$darkSecondaryLight: #e6f4f1;
|
||||
$darkSecondaryMain: #2ca58d;
|
||||
$darkSecondaryDark: #279d85;
|
||||
$darkSecondary200: #96d2c6;
|
||||
$darkSecondary800: #1b8a70;
|
||||
|
||||
// text variants
|
||||
$darkTextTitle: #d7dcec;
|
||||
$darkTextPrimary: #bdc8f0;
|
||||
$darkTextSecondary: #8492c4;
|
||||
|
||||
// ==============================|| JAVASCRIPT ||============================== //
|
||||
|
||||
:export {
|
||||
// paper & background
|
||||
paper: $paper;
|
||||
|
||||
// primary
|
||||
primaryLight: $primaryLight;
|
||||
primary200: $primary200;
|
||||
primaryMain: $primaryMain;
|
||||
primaryDark: $primaryDark;
|
||||
primary800: $primary800;
|
||||
|
||||
// secondary
|
||||
secondaryLight: $secondaryLight;
|
||||
secondary200: $secondary200;
|
||||
secondaryMain: $secondaryMain;
|
||||
secondaryDark: $secondaryDark;
|
||||
secondary800: $secondary800;
|
||||
|
||||
// success
|
||||
successLight: $successLight;
|
||||
success200: $success200;
|
||||
successMain: $successMain;
|
||||
successDark: $successDark;
|
||||
|
||||
// error
|
||||
errorLight: $errorLight;
|
||||
errorMain: $errorMain;
|
||||
errorDark: $errorDark;
|
||||
|
||||
// orange
|
||||
orangeLight: $orangeLight;
|
||||
orangeMain: $orangeMain;
|
||||
orangeDark: $orangeDark;
|
||||
|
||||
// warning
|
||||
warningLight: $warningLight;
|
||||
warningMain: $warningMain;
|
||||
warningDark: $warningDark;
|
||||
|
||||
// grey
|
||||
grey50: $grey50;
|
||||
grey100: $grey100;
|
||||
grey200: $grey200;
|
||||
grey300: $grey300;
|
||||
grey500: $grey500;
|
||||
grey600: $grey600;
|
||||
grey700: $grey700;
|
||||
grey900: $grey900;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
darkPaper: $darkPaper;
|
||||
darkBackground: $darkBackground;
|
||||
|
||||
// dark 800 & 900
|
||||
darkLevel1: $darkLevel1;
|
||||
darkLevel2: $darkLevel2;
|
||||
|
||||
// text variants
|
||||
darkTextTitle: $darkTextTitle;
|
||||
darkTextPrimary: $darkTextPrimary;
|
||||
darkTextSecondary: $darkTextSecondary;
|
||||
|
||||
// primary dark
|
||||
darkPrimaryLight: $darkPrimaryLight;
|
||||
darkPrimaryMain: $darkPrimaryMain;
|
||||
darkPrimaryDark: $darkPrimaryDark;
|
||||
darkPrimary200: $darkPrimary200;
|
||||
darkPrimary800: $darkPrimary800;
|
||||
|
||||
// secondary dark
|
||||
darkSecondaryLight: $darkSecondaryLight;
|
||||
darkSecondaryMain: $darkSecondaryMain;
|
||||
darkSecondaryDark: $darkSecondaryDark;
|
||||
darkSecondary200: $darkSecondary200;
|
||||
darkSecondary800: $darkSecondary800;
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
// paper & background
|
||||
$paper: #ffffff;
|
||||
|
||||
// primary
|
||||
$primaryLight: #e8eaf6;
|
||||
$primaryMain: #3f51b5;
|
||||
$primaryDark: #3949ab;
|
||||
$primary200: #9fa8da;
|
||||
$primary800: #283593;
|
||||
|
||||
// secondary
|
||||
$secondaryLight: #e8eaf6;
|
||||
$secondaryMain: #3f51b5;
|
||||
$secondaryDark: #3949ab;
|
||||
$secondary200: #9fa8da;
|
||||
$secondary800: #283593;
|
||||
|
||||
// success Colors
|
||||
$successLight: #b9f6ca;
|
||||
$success200: #69f0ae;
|
||||
$successMain: #00e676;
|
||||
$successDark: #00c853;
|
||||
|
||||
// error
|
||||
$errorLight: #ef9a9a;
|
||||
$errorMain: #f44336;
|
||||
$errorDark: #c62828;
|
||||
|
||||
// orange
|
||||
$orangeLight: #fbe9e7;
|
||||
$orangeMain: #ffab91;
|
||||
$orangeDark: #d84315;
|
||||
|
||||
// warning
|
||||
$warningLight: #fff8e1;
|
||||
$warningMain: #ffe57f;
|
||||
$warningDark: #ffc107;
|
||||
|
||||
// grey
|
||||
$grey50: #fafafa;
|
||||
$grey100: #f5f5f5;
|
||||
$grey200: #eeeeee;
|
||||
$grey300: #e0e0e0;
|
||||
$grey500: #9e9e9e;
|
||||
$grey600: #757575;
|
||||
$grey700: #616161;
|
||||
$grey900: #212121;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
$darkBackground: #1a223f; // level 3
|
||||
$darkPaper: #111936; // level 4
|
||||
|
||||
// dark 800 & 900
|
||||
$darkLevel1: #29314f; // level 1
|
||||
$darkLevel2: #212946; // level 2
|
||||
|
||||
// primary dark
|
||||
$darkPrimaryLight: #eeedfd;
|
||||
$darkPrimaryMain: #7267ef;
|
||||
$darkPrimaryDark: #6a5fed;
|
||||
$darkPrimary200: #b9b3f7;
|
||||
$darkPrimary800: #554ae8;
|
||||
|
||||
// secondary dark
|
||||
$darkSecondaryLight: #eeedfd;
|
||||
$darkSecondaryMain: #7267ef;
|
||||
$darkSecondaryDark: #6a5fed;
|
||||
$darkSecondary200: #b9b3f7;
|
||||
$darkSecondary800: #554ae8;
|
||||
|
||||
// text variants
|
||||
$darkTextTitle: #d7dcec;
|
||||
$darkTextPrimary: #bdc8f0;
|
||||
$darkTextSecondary: #8492c4;
|
||||
|
||||
// ==============================|| JAVASCRIPT ||============================== //
|
||||
|
||||
:export {
|
||||
// paper & background
|
||||
paper: $paper;
|
||||
|
||||
// primary
|
||||
primaryLight: $primaryLight;
|
||||
primary200: $primary200;
|
||||
primaryMain: $primaryMain;
|
||||
primaryDark: $primaryDark;
|
||||
primary800: $primary800;
|
||||
|
||||
// secondary
|
||||
secondaryLight: $secondaryLight;
|
||||
secondary200: $secondary200;
|
||||
secondaryMain: $secondaryMain;
|
||||
secondaryDark: $secondaryDark;
|
||||
secondary800: $secondary800;
|
||||
|
||||
// success
|
||||
successLight: $successLight;
|
||||
success200: $success200;
|
||||
successMain: $successMain;
|
||||
successDark: $successDark;
|
||||
|
||||
// error
|
||||
errorLight: $errorLight;
|
||||
errorMain: $errorMain;
|
||||
errorDark: $errorDark;
|
||||
|
||||
// orange
|
||||
orangeLight: $orangeLight;
|
||||
orangeMain: $orangeMain;
|
||||
orangeDark: $orangeDark;
|
||||
|
||||
// warning
|
||||
warningLight: $warningLight;
|
||||
warningMain: $warningMain;
|
||||
warningDark: $warningDark;
|
||||
|
||||
// grey
|
||||
grey50: $grey50;
|
||||
grey100: $grey100;
|
||||
grey200: $grey200;
|
||||
grey300: $grey300;
|
||||
grey500: $grey500;
|
||||
grey600: $grey600;
|
||||
grey700: $grey700;
|
||||
grey900: $grey900;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
darkPaper: $darkPaper;
|
||||
darkBackground: $darkBackground;
|
||||
|
||||
// dark 800 & 900
|
||||
darkLevel1: $darkLevel1;
|
||||
darkLevel2: $darkLevel2;
|
||||
|
||||
// text variants
|
||||
darkTextTitle: $darkTextTitle;
|
||||
darkTextPrimary: $darkTextPrimary;
|
||||
darkTextSecondary: $darkTextSecondary;
|
||||
|
||||
// primary dark
|
||||
darkPrimaryLight: $darkPrimaryLight;
|
||||
darkPrimaryMain: $darkPrimaryMain;
|
||||
darkPrimaryDark: $darkPrimaryDark;
|
||||
darkPrimary200: $darkPrimary200;
|
||||
darkPrimary800: $darkPrimary800;
|
||||
|
||||
// secondary dark
|
||||
darkSecondaryLight: $darkSecondaryLight;
|
||||
darkSecondaryMain: $darkSecondaryMain;
|
||||
darkSecondaryDark: $darkSecondaryDark;
|
||||
darkSecondary200: $darkSecondary200;
|
||||
darkSecondary800: $darkSecondary800;
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
// paper & background
|
||||
$paper: #ffffff;
|
||||
|
||||
// primary
|
||||
$primaryLight: #e3f2fd;
|
||||
$primaryMain: #2196f3;
|
||||
$primaryDark: #1e88e5;
|
||||
$primary200: #90caf9;
|
||||
$primary800: #1565c0;
|
||||
|
||||
// secondary
|
||||
$secondaryLight: #ede7f6;
|
||||
$secondaryMain: #673ab7;
|
||||
$secondaryDark: #5e35b1;
|
||||
$secondary200: #b39ddb;
|
||||
$secondary800: #4527a0;
|
||||
|
||||
// success Colors
|
||||
$successLight: #b9f6ca;
|
||||
$success200: #69f0ae;
|
||||
$successMain: #00e676;
|
||||
$successDark: #00c853;
|
||||
|
||||
// error
|
||||
$errorLight: #ef9a9a;
|
||||
$errorMain: #f44336;
|
||||
$errorDark: #c62828;
|
||||
|
||||
// orange
|
||||
$orangeLight: #fbe9e7;
|
||||
$orangeMain: #ffab91;
|
||||
$orangeDark: #d84315;
|
||||
|
||||
// warning
|
||||
$warningLight: #fff8e1;
|
||||
$warningMain: #ffe57f;
|
||||
$warningDark: #ffc107;
|
||||
|
||||
// grey
|
||||
$grey50: #fafafa;
|
||||
$grey100: #f5f5f5;
|
||||
$grey200: #eeeeee;
|
||||
$grey300: #e0e0e0;
|
||||
$grey500: #9e9e9e;
|
||||
$grey600: #757575;
|
||||
$grey700: #616161;
|
||||
$grey900: #212121;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
$darkBackground: #1a223f; // level 3
|
||||
$darkPaper: #111936; // level 4
|
||||
|
||||
// dark 800 & 900
|
||||
$darkLevel1: #29314f; // level 1
|
||||
$darkLevel2: #212946; // level 2
|
||||
|
||||
// primary dark
|
||||
$darkPrimaryLight: #e3f2fd;
|
||||
$darkPrimaryMain: #2196f3;
|
||||
$darkPrimaryDark: #1e88e5;
|
||||
$darkPrimary200: #90caf9;
|
||||
$darkPrimary800: #1565c0;
|
||||
|
||||
// secondary dark
|
||||
$darkSecondaryLight: #d1c4e9;
|
||||
$darkSecondaryMain: #7c4dff;
|
||||
$darkSecondaryDark: #651fff;
|
||||
$darkSecondary200: #b39ddb;
|
||||
$darkSecondary800: #6200ea;
|
||||
|
||||
// text variants
|
||||
$darkTextTitle: #d7dcec;
|
||||
$darkTextPrimary: #bdc8f0;
|
||||
$darkTextSecondary: #8492c4;
|
||||
|
||||
// ==============================|| JAVASCRIPT ||============================== //
|
||||
|
||||
:export {
|
||||
// paper & background
|
||||
paper: $paper;
|
||||
|
||||
// primary
|
||||
primaryLight: $primaryLight;
|
||||
primary200: $primary200;
|
||||
primaryMain: $primaryMain;
|
||||
primaryDark: $primaryDark;
|
||||
primary800: $primary800;
|
||||
|
||||
// secondary
|
||||
secondaryLight: $secondaryLight;
|
||||
secondary200: $secondary200;
|
||||
secondaryMain: $secondaryMain;
|
||||
secondaryDark: $secondaryDark;
|
||||
secondary800: $secondary800;
|
||||
|
||||
// success
|
||||
successLight: $successLight;
|
||||
success200: $success200;
|
||||
successMain: $successMain;
|
||||
successDark: $successDark;
|
||||
|
||||
// error
|
||||
errorLight: $errorLight;
|
||||
errorMain: $errorMain;
|
||||
errorDark: $errorDark;
|
||||
|
||||
// orange
|
||||
orangeLight: $orangeLight;
|
||||
orangeMain: $orangeMain;
|
||||
orangeDark: $orangeDark;
|
||||
|
||||
// warning
|
||||
warningLight: $warningLight;
|
||||
warningMain: $warningMain;
|
||||
warningDark: $warningDark;
|
||||
|
||||
// grey
|
||||
grey50: $grey50;
|
||||
grey100: $grey100;
|
||||
grey200: $grey200;
|
||||
grey300: $grey300;
|
||||
grey500: $grey500;
|
||||
grey600: $grey600;
|
||||
grey700: $grey700;
|
||||
grey900: $grey900;
|
||||
|
||||
// ==============================|| DARK THEME VARIANTS ||============================== //
|
||||
|
||||
// paper & background
|
||||
darkPaper: $darkPaper;
|
||||
darkBackground: $darkBackground;
|
||||
|
||||
// dark 800 & 900
|
||||
darkLevel1: $darkLevel1;
|
||||
darkLevel2: $darkLevel2;
|
||||
|
||||
// text variants
|
||||
darkTextTitle: $darkTextTitle;
|
||||
darkTextPrimary: $darkTextPrimary;
|
||||
darkTextSecondary: $darkTextSecondary;
|
||||
|
||||
// primary dark
|
||||
darkPrimaryLight: $darkPrimaryLight;
|
||||
darkPrimaryMain: $darkPrimaryMain;
|
||||
darkPrimaryDark: $darkPrimaryDark;
|
||||
darkPrimary200: $darkPrimary200;
|
||||
darkPrimary800: $darkPrimary800;
|
||||
|
||||
// secondary dark
|
||||
darkSecondaryLight: $darkSecondaryLight;
|
||||
darkSecondaryMain: $darkSecondaryMain;
|
||||
darkSecondaryDark: $darkSecondaryDark;
|
||||
darkSecondary200: $darkSecondary200;
|
||||
darkSecondary800: $darkSecondary800;
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
// color variants
|
||||
@import 'themes-vars.module.scss';
|
||||
|
||||
// third-party
|
||||
@import '~react-perfect-scrollbar/dist/css/styles.css';
|
||||
@import '~slick-carousel/slick/slick.css';
|
||||
@import '~slick-carousel/slick/slick-theme.css';
|
||||
|
||||
// ==============================|| LIGHT BOX ||============================== //
|
||||
.slick-arrow:before {
|
||||
color: $grey500;
|
||||
}
|
||||
|
||||
// ==============================|| LIGHT BOX ||============================== //
|
||||
.fullscreen .react-images__blanket {
|
||||
z-index: 1200;
|
||||
}
|
||||
|
||||
// ==============================|| APEXCHART ||============================== //
|
||||
|
||||
.apexcharts-legend-series .apexcharts-legend-marker {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
// ==============================|| PERFECT SCROLLBAR ||============================== //
|
||||
|
||||
.scrollbar-container {
|
||||
.ps__rail-y {
|
||||
&:hover > .ps__thumb-y,
|
||||
&:focus > .ps__thumb-y,
|
||||
&.ps--clicking .ps__thumb-y {
|
||||
background-color: $grey500;
|
||||
width: 5px;
|
||||
}
|
||||
}
|
||||
.ps__thumb-y {
|
||||
background-color: $grey500;
|
||||
border-radius: 6px;
|
||||
width: 5px;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.scrollbar-container.ps,
|
||||
.scrollbar-container > .ps {
|
||||
&.ps--active-y > .ps__rail-y {
|
||||
width: 5px;
|
||||
background-color: transparent !important;
|
||||
z-index: 999;
|
||||
&:hover,
|
||||
&.ps--clicking {
|
||||
width: 5px;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
&.ps--scrolling-y > .ps__rail-y,
|
||||
&.ps--scrolling-x > .ps__rail-x {
|
||||
opacity: 0.4;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================|| ANIMATION KEYFRAMES ||============================== //
|
||||
|
||||
@keyframes wings {
|
||||
50% {
|
||||
transform: translateY(-40px);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%,
|
||||
20%,
|
||||
53%,
|
||||
to {
|
||||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
transform: translateZ(0);
|
||||
}
|
||||
40%,
|
||||
43% {
|
||||
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
||||
transform: translate3d(0, -5px, 0);
|
||||
}
|
||||
70% {
|
||||
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
||||
transform: translate3d(0, -7px, 0);
|
||||
}
|
||||
80% {
|
||||
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
transform: translateZ(0);
|
||||
}
|
||||
90% {
|
||||
transform: translate3d(0, -2px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideY {
|
||||
0%,
|
||||
50%,
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
25% {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
75% {
|
||||
transform: translateY(10px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideX {
|
||||
0%,
|
||||
50%,
|
||||
100% {
|
||||
transform: translateX(0px);
|
||||
}
|
||||
25% {
|
||||
transform: translateX(-10px);
|
||||
}
|
||||
75% {
|
||||
transform: translateX(10px);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
export const JWT_API = {
|
||||
secret: 'SECRET-KEY',
|
||||
timeout: '1 days'
|
||||
};
|
||||
|
||||
export const FIREBASE_API = {
|
||||
apiKey: 'AIzaSyBernKzdSojh_vWXBHt0aRhf5SC9VLChbM',
|
||||
authDomain: 'berry-material-react.firebaseapp.com',
|
||||
projectId: 'berry-material-react',
|
||||
storageBucket: 'berry-material-react.appspot.com',
|
||||
messagingSenderId: '901111229354',
|
||||
appId: '1:901111229354:web:a5ae5aa95486297d69d9d3',
|
||||
measurementId: 'G-MGJHSL8XW3'
|
||||
};
|
||||
|
||||
export const AUTH0_API = {
|
||||
client_id: '7T4IlWis4DKHSbG8JAye4Ipk0rvXkH9V',
|
||||
domain: 'dev-w0-vxep3.us.auth0.com'
|
||||
};
|
||||
|
||||
export const AWS_API = {
|
||||
poolId: 'us-east-1_AOfOTXLvD',
|
||||
appClientId: '3eau2osduslvb7vks3vsh9t7b0'
|
||||
};
|
||||
|
||||
// basename: only at build time to set, and Don't add '/' at end off BASENAME for breadcrumbs, also Don't put only '/' use blank('') instead,
|
||||
// like '/berry-material-react/react/default'
|
||||
export const BASE_PATH = '';
|
||||
|
||||
export const DASHBOARD_PATH = '/sample-page';
|
||||
|
||||
const config = {
|
||||
fontFamily: `'Roboto', sans-serif`,
|
||||
borderRadius: 8,
|
||||
outlinedFilled: true,
|
||||
navType: 'light', // light, dark
|
||||
presetColor: 'default', // default, theme1, theme2, theme3, theme4, theme5, theme6
|
||||
locale: 'en', // 'en' - English, 'fr' - French, 'ro' - Romanian, 'zh' - Chinese
|
||||
rtlLayout: false,
|
||||
container: false
|
||||
};
|
||||
|
||||
export default config;
|
@ -0,0 +1,153 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { createContext, useEffect, useReducer } from 'react';
|
||||
|
||||
// third-party
|
||||
import { CognitoUser, CognitoUserPool, CognitoUserAttribute, AuthenticationDetails } from 'amazon-cognito-identity-js';
|
||||
|
||||
// reducer - state management
|
||||
import { LOGIN, LOGOUT } from 'store/actions';
|
||||
import accountReducer from 'store/accountReducer';
|
||||
|
||||
// project imports
|
||||
import Loader from 'ui-component/Loader';
|
||||
import { AWS_API } from 'config';
|
||||
|
||||
// constant
|
||||
const initialState = {
|
||||
isLoggedIn: false,
|
||||
isInitialized: false,
|
||||
user: null
|
||||
};
|
||||
|
||||
export const userPool = new CognitoUserPool({
|
||||
UserPoolId: AWS_API.poolId || '',
|
||||
ClientId: AWS_API.appClientId || ''
|
||||
});
|
||||
|
||||
const setSession = (serviceToken? | null) => {
|
||||
if (serviceToken) {
|
||||
localStorage.setItem('serviceToken', serviceToken);
|
||||
} else {
|
||||
localStorage.removeItem('serviceToken');
|
||||
}
|
||||
};
|
||||
|
||||
// ==============================|| AWS Cognito CONTEXT & PROVIDER ||============================== //
|
||||
const AWSCognitoContext = createContext(null);
|
||||
|
||||
export const AWSCognitoProvider = ({ children }) => {
|
||||
const [state, dispatch] = useReducer(accountReducer, initialState);
|
||||
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
try {
|
||||
const serviceToken = window.localStorage.getItem('serviceToken');
|
||||
if (serviceToken) {
|
||||
setSession(serviceToken);
|
||||
dispatch({
|
||||
type: LOGIN,
|
||||
payload: {
|
||||
isLoggedIn: true,
|
||||
user: {
|
||||
name: 'Betty'
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: LOGOUT
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
dispatch({
|
||||
type: LOGOUT
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
||||
}, []);
|
||||
|
||||
const login = async (email, password) => {
|
||||
const usr = new CognitoUser({
|
||||
Username: email,
|
||||
Pool: userPool
|
||||
});
|
||||
|
||||
const authData = new AuthenticationDetails({
|
||||
Username: email,
|
||||
Password: password
|
||||
});
|
||||
|
||||
usr.authenticateUser(authData, {
|
||||
onSuccess: (session) => {
|
||||
setSession(session.getAccessToken().getJwtToken());
|
||||
|
||||
dispatch({
|
||||
type: LOGIN,
|
||||
payload: {
|
||||
isLoggedIn: true,
|
||||
user: {
|
||||
email: authData.getUsername(),
|
||||
name: 'John Doe'
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
onFailure: (_err) => {},
|
||||
newPasswordRequired: (userAttributes, requiredAttributes) => {
|
||||
// // User was signed up by an admin and must provide new
|
||||
// // password and required attributes, if any, to complete
|
||||
// // authentication.
|
||||
// // the api doesn't accept this field back
|
||||
// delete userAttributes.email_verified;
|
||||
// // unsure about this field, but I don't send this back
|
||||
// delete userAttributes.phone_number_verified;
|
||||
// // Get these details and call
|
||||
// usr.completeNewPasswordChallenge(password, userAttributes, requiredAttributes);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const register = (email, password, firstName, lastName) =>
|
||||
new Promise((success, rej) => {
|
||||
userPool.signUp(
|
||||
email,
|
||||
password,
|
||||
[
|
||||
new CognitoUserAttribute({ Name: 'email', Value: email }),
|
||||
new CognitoUserAttribute({ Name: 'name', Value: `${firstName} ${lastName}` })
|
||||
],
|
||||
[],
|
||||
async (err, result) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
return;
|
||||
}
|
||||
success(result);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const logout = () => {
|
||||
const loggedInUser = userPool.getCurrentUser();
|
||||
if (loggedInUser) {
|
||||
setSession(null);
|
||||
loggedInUser.signOut();
|
||||
dispatch({ type: LOGOUT });
|
||||
}
|
||||
};
|
||||
|
||||
if (state.isInitialized !== undefined && !state.isInitialized) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
return <AWSCognitoContext.Provider value={{ ...state, login, logout, register }}>{children}</AWSCognitoContext.Provider>;
|
||||
};
|
||||
|
||||
AWSCognitoProvider.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default AWSCognitoContext;
|
@ -0,0 +1,115 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { createContext, useEffect, useReducer } from 'react';
|
||||
|
||||
// third-party
|
||||
import { Auth0Client } from '@auth0/auth0-spa-js';
|
||||
|
||||
// reducer - state management
|
||||
import { LOGIN, LOGOUT } from 'store/actions';
|
||||
import accountReducer from 'store/accountReducer';
|
||||
|
||||
// project imports
|
||||
import Loader from 'ui-component/Loader';
|
||||
import { AUTH0_API } from 'config';
|
||||
|
||||
// constant
|
||||
let auth0Client;
|
||||
|
||||
const initialState = {
|
||||
isLoggedIn: false,
|
||||
isInitialized: false,
|
||||
user: null
|
||||
};
|
||||
|
||||
// ==============================|| AUTH0 CONTEXT & PROVIDER ||============================== //
|
||||
|
||||
const Auth0Context = createContext(null);
|
||||
|
||||
export const Auth0Provider = ({ children }) => {
|
||||
const [state, dispatch] = useReducer(accountReducer, initialState);
|
||||
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
try {
|
||||
auth0Client = new Auth0Client({
|
||||
redirect_uri: window.location.origin,
|
||||
...AUTH0_API
|
||||
});
|
||||
|
||||
await auth0Client.checkSession();
|
||||
const isLoggedIn = await auth0Client.isAuthenticated();
|
||||
|
||||
if (isLoggedIn) {
|
||||
const user = await auth0Client.getUser();
|
||||
|
||||
dispatch({
|
||||
type: LOGIN,
|
||||
payload: {
|
||||
isLoggedIn: true,
|
||||
user: {
|
||||
id: user?.sub,
|
||||
email: user?.email
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: LOGOUT
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
dispatch({
|
||||
type: LOGOUT
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
||||
}, []);
|
||||
|
||||
const login = async (options) => {
|
||||
await auth0Client.loginWithPopup(options);
|
||||
const isLoggedIn = await auth0Client.isAuthenticated();
|
||||
|
||||
if (isLoggedIn) {
|
||||
const user = await auth0Client.getUser();
|
||||
dispatch({
|
||||
type: LOGIN,
|
||||
payload: {
|
||||
isLoggedIn: true,
|
||||
user: {
|
||||
id: user?.sub,
|
||||
avatar: user?.picture,
|
||||
email: user?.email,
|
||||
name: user?.name,
|
||||
tier: 'Premium'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
auth0Client.logout();
|
||||
|
||||
dispatch({
|
||||
type: LOGOUT
|
||||
});
|
||||
};
|
||||
|
||||
const resetPassword = (email) => {};
|
||||
|
||||
const updateProfile = () => {};
|
||||
|
||||
if (state.isInitialized !== undefined && !state.isInitialized) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
return <Auth0Context.Provider value={{ ...state, login, logout, resetPassword, updateProfile }}>{children}</Auth0Context.Provider>;
|
||||
};
|
||||
|
||||
Auth0Provider.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default Auth0Context;
|
@ -0,0 +1,115 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { createContext } from 'react';
|
||||
|
||||
// project import
|
||||
import defaultConfig from 'config';
|
||||
import useLocalStorage from 'hooks/useLocalStorage';
|
||||
|
||||
// initial state
|
||||
const initialState = {
|
||||
...defaultConfig,
|
||||
onChangeMenuType: () => {},
|
||||
onChangePresetColor: () => {},
|
||||
onChangeLocale: () => {},
|
||||
onChangeRTL: () => {},
|
||||
onChangeContainer: () => {},
|
||||
onChangeFontFamily: () => {},
|
||||
onChangeBorderRadius: () => {},
|
||||
onChangeOutlinedField: () => {}
|
||||
};
|
||||
|
||||
// ==============================|| CONFIG CONTEXT & PROVIDER ||============================== //
|
||||
|
||||
const ConfigContext = createContext(initialState);
|
||||
|
||||
function ConfigProvider({ children }) {
|
||||
const [config, setConfig] = useLocalStorage('berry-config', {
|
||||
fontFamily: initialState.fontFamily,
|
||||
borderRadius: initialState.borderRadius,
|
||||
outlinedFilled: initialState.outlinedFilled,
|
||||
navType: initialState.navType,
|
||||
presetColor: initialState.presetColor,
|
||||
locale: initialState.locale,
|
||||
rtlLayout: initialState.rtlLayout
|
||||
});
|
||||
|
||||
const onChangeMenuType = (navType) => {
|
||||
setConfig({
|
||||
...config,
|
||||
navType
|
||||
});
|
||||
};
|
||||
|
||||
const onChangePresetColor = (presetColor) => {
|
||||
setConfig({
|
||||
...config,
|
||||
presetColor
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeLocale = (locale) => {
|
||||
setConfig({
|
||||
...config,
|
||||
locale
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeRTL = (rtlLayout) => {
|
||||
setConfig({
|
||||
...config,
|
||||
rtlLayout
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeContainer = () => {
|
||||
setConfig({
|
||||
...config,
|
||||
container: !config.container
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeFontFamily = (fontFamily) => {
|
||||
setConfig({
|
||||
...config,
|
||||
fontFamily
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeBorderRadius = (event, newValue) => {
|
||||
setConfig({
|
||||
...config,
|
||||
borderRadius: newValue
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeOutlinedField = (outlinedFilled) => {
|
||||
setConfig({
|
||||
...config,
|
||||
outlinedFilled
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<ConfigContext.Provider
|
||||
value={{
|
||||
...config,
|
||||
onChangeMenuType,
|
||||
onChangePresetColor,
|
||||
onChangeLocale,
|
||||
onChangeRTL,
|
||||
onChangeContainer,
|
||||
onChangeFontFamily,
|
||||
onChangeBorderRadius,
|
||||
onChangeOutlinedField
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ConfigContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
ConfigProvider.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export { ConfigProvider, ConfigContext };
|
@ -0,0 +1,103 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { createContext, useEffect, useReducer } from 'react';
|
||||
|
||||
// third-party
|
||||
import firebase from 'firebase/compat/app';
|
||||
import 'firebase/compat/auth';
|
||||
|
||||
// action - state management
|
||||
import { LOGIN, LOGOUT } from 'store/actions';
|
||||
import accountReducer from 'store/accountReducer';
|
||||
|
||||
// project imports
|
||||
import Loader from 'ui-component/Loader';
|
||||
import { FIREBASE_API } from 'config';
|
||||
|
||||
// firebase initialize
|
||||
if (!firebase.apps.length) {
|
||||
firebase.initializeApp(FIREBASE_API);
|
||||
}
|
||||
|
||||
// const
|
||||
const initialState = {
|
||||
isLoggedIn: false,
|
||||
isInitialized: false,
|
||||
user: null
|
||||
};
|
||||
|
||||
// ==============================|| FIREBASE CONTEXT & PROVIDER ||============================== //
|
||||
|
||||
const FirebaseContext = createContext(null);
|
||||
|
||||
export const FirebaseProvider = ({ children }) => {
|
||||
const [state, dispatch] = useReducer(accountReducer, initialState);
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
firebase.auth().onAuthStateChanged((user) => {
|
||||
if (user) {
|
||||
dispatch({
|
||||
type: LOGIN,
|
||||
payload: {
|
||||
isLoggedIn: true,
|
||||
user: {
|
||||
id: user.uid,
|
||||
email: user.email,
|
||||
name: user.displayName || 'John Doe'
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: LOGOUT
|
||||
});
|
||||
}
|
||||
}),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const firebaseEmailPasswordSignIn = (email, password) => firebase.auth().signInWithEmailAndPassword(email, password);
|
||||
|
||||
const firebaseGoogleSignIn = () => {
|
||||
const provider = new firebase.auth.GoogleAuthProvider();
|
||||
|
||||
return firebase.auth().signInWithPopup(provider);
|
||||
};
|
||||
|
||||
const firebaseRegister = async (email, password) => firebase.auth().createUserWithEmailAndPassword(email, password);
|
||||
|
||||
const logout = () => firebase.auth().signOut();
|
||||
|
||||
const resetPassword = async (email) => {
|
||||
await firebase.auth().sendPasswordResetEmail(email);
|
||||
};
|
||||
|
||||
const updateProfile = () => {};
|
||||
if (state.isInitialized !== undefined && !state.isInitialized) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
return (
|
||||
<FirebaseContext.Provider
|
||||
value={{
|
||||
...state,
|
||||
firebaseRegister,
|
||||
firebaseEmailPasswordSignIn,
|
||||
login: () => {},
|
||||
firebaseGoogleSignIn,
|
||||
logout,
|
||||
resetPassword,
|
||||
updateProfile
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</FirebaseContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
FirebaseProvider.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default FirebaseContext;
|
@ -0,0 +1,144 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { createContext, useEffect, useReducer } from 'react';
|
||||
|
||||
// third-party
|
||||
import { Chance } from 'chance';
|
||||
import jwtDecode from 'jwt-decode';
|
||||
|
||||
// reducer - state management
|
||||
import { LOGIN, LOGOUT } from 'store/actions';
|
||||
import accountReducer from 'store/accountReducer';
|
||||
|
||||
// project imports
|
||||
import Loader from 'ui-component/Loader';
|
||||
import axios from 'utils/axios';
|
||||
|
||||
const chance = new Chance();
|
||||
|
||||
// constant
|
||||
const initialState = {
|
||||
isLoggedIn: false,
|
||||
isInitialized: false,
|
||||
user: null
|
||||
};
|
||||
|
||||
const verifyToken = (serviceToken) => {
|
||||
if (!serviceToken) {
|
||||
return false;
|
||||
}
|
||||
const decoded = jwtDecode(serviceToken);
|
||||
/**
|
||||
* Property 'exp' does not exist on type '<T = unknown>(token, options?: JwtDecodeOptions | undefined) => T'.
|
||||
*/
|
||||
return decoded.exp > Date.now() / 1000;
|
||||
};
|
||||
|
||||
const setSession = (serviceToken) => {
|
||||
if (serviceToken) {
|
||||
localStorage.setItem('serviceToken', serviceToken);
|
||||
axios.defaults.headers.common.Authorization = `Bearer ${serviceToken}`;
|
||||
} else {
|
||||
localStorage.removeItem('serviceToken');
|
||||
delete axios.defaults.headers.common.Authorization;
|
||||
}
|
||||
};
|
||||
|
||||
// ==============================|| JWT CONTEXT & PROVIDER ||============================== //
|
||||
const JWTContext = createContext(null);
|
||||
|
||||
export const JWTProvider = ({ children }) => {
|
||||
const [state, dispatch] = useReducer(accountReducer, initialState);
|
||||
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
try {
|
||||
const serviceToken = window.localStorage.getItem('serviceToken');
|
||||
if (serviceToken && verifyToken(serviceToken)) {
|
||||
setSession(serviceToken);
|
||||
const response = await axios.get('/api/account/me');
|
||||
const { user } = response.data;
|
||||
dispatch({
|
||||
type: LOGIN,
|
||||
payload: {
|
||||
isLoggedIn: true,
|
||||
user
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: LOGOUT
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
dispatch({
|
||||
type: LOGOUT
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
||||
}, []);
|
||||
|
||||
const login = async (email, password) => {
|
||||
const response = await axios.post('/api/account/login', { email, password });
|
||||
const { serviceToken, user } = response.data;
|
||||
setSession(serviceToken);
|
||||
dispatch({
|
||||
type: LOGIN,
|
||||
payload: {
|
||||
isLoggedIn: true,
|
||||
user
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const register = async (email, password, firstName, lastName) => {
|
||||
// todo: this flow need to be recode as it not verified
|
||||
const id = chance.bb_pin();
|
||||
const response = await axios.post('/api/account/register', {
|
||||
id,
|
||||
email,
|
||||
password,
|
||||
firstName,
|
||||
lastName
|
||||
});
|
||||
let users = response.data;
|
||||
|
||||
if (window.localStorage.getItem('users') !== undefined && window.localStorage.getItem('users') !== null) {
|
||||
const localUsers = window.localStorage.getItem('users');
|
||||
users = [
|
||||
...JSON.parse(localUsers),
|
||||
{
|
||||
id,
|
||||
email,
|
||||
password,
|
||||
name: `${firstName} ${lastName}`
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
window.localStorage.setItem('users', JSON.stringify(users));
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
setSession(null);
|
||||
dispatch({ type: LOGOUT });
|
||||
};
|
||||
|
||||
const resetPassword = (email) => console.log(email);
|
||||
|
||||
const updateProfile = () => {};
|
||||
|
||||
if (state.isInitialized !== undefined && !state.isInitialized) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
return <JWTContext.Provider value={{ ...state, login, logout, register, resetPassword, updateProfile }}>{children}</JWTContext.Provider>;
|
||||
};
|
||||
|
||||
JWTProvider.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default JWTContext;
|
@ -0,0 +1,19 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
// auth provider
|
||||
import AuthContext from 'contexts/FirebaseContext';
|
||||
// import AuthContext from 'contexts/Auth0Context';
|
||||
// import AuthContext from 'contexts/JWTContext';
|
||||
// import AuthContext from 'contexts/AWSCognitoContext';
|
||||
|
||||
// ==============================|| AUTH HOOKS ||============================== //
|
||||
|
||||
const useAuth = () => {
|
||||
const context = useContext(AuthContext);
|
||||
|
||||
if (!context) throw new Error('context must be use inside provider');
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
export default useAuth;
|
@ -0,0 +1,8 @@
|
||||
import { useContext } from 'react';
|
||||
import { ConfigContext } from 'contexts/ConfigContext';
|
||||
|
||||
// ==============================|| CONFIG - HOOKS ||============================== //
|
||||
|
||||
const useConfig = () => useContext(ConfigContext);
|
||||
|
||||
export default useConfig;
|
@ -0,0 +1,33 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
// ==============================|| CONFIG - LOCAL STORAGE ||============================== //
|
||||
|
||||
export default function useLocalStorage(key, defaultValue) {
|
||||
const [value, setValue] = useState(() => {
|
||||
const storedValue = localStorage.getItem(key);
|
||||
return storedValue === null ? defaultValue : JSON.parse(storedValue);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (e) => {
|
||||
if (e.storageArea === localStorage && e.key === key) {
|
||||
setValue(e.newValue ? JSON.parse(e.newValue) : e.newValue);
|
||||
}
|
||||
};
|
||||
window.addEventListener('storage', listener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('storage', listener);
|
||||
};
|
||||
}, [key, defaultValue]);
|
||||
|
||||
const setValueInLocalStorage = (newValue) => {
|
||||
setValue((currentValue) => {
|
||||
const result = typeof newValue === 'function' ? newValue(currentValue) : newValue;
|
||||
localStorage.setItem(key, JSON.stringify(result));
|
||||
return result;
|
||||
});
|
||||
};
|
||||
|
||||
return [value, setValueInLocalStorage];
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
// ==============================|| ELEMENT REFERENCE HOOKS ||============================== //
|
||||
|
||||
const useScriptRef = () => {
|
||||
const scripted = useRef(true);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
scripted.current = false;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return scripted;
|
||||
};
|
||||
|
||||
export default useScriptRef;
|
@ -0,0 +1,42 @@
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
// third party
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import { PersistGate } from 'redux-persist/integration/react';
|
||||
|
||||
// project imports
|
||||
import App from 'App';
|
||||
import { BASE_PATH } from 'config';
|
||||
import { store, persister } from 'store';
|
||||
import * as serviceWorker from 'serviceWorker';
|
||||
import reportWebVitals from 'reportWebVitals';
|
||||
import { ConfigProvider } from 'contexts/ConfigContext';
|
||||
|
||||
// style + assets
|
||||
import 'assets/scss/style.scss';
|
||||
|
||||
// ==============================|| REACT DOM RENDER ||============================== //
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<PersistGate loading={null} persistor={persister}>
|
||||
<ConfigProvider>
|
||||
<BrowserRouter basename={BASE_PATH}>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</ConfigProvider>
|
||||
</PersistGate>
|
||||
</Provider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
// unregister() to register() below. Note this comes with some pitfalls.
|
||||
// Learn more about service workers: https://bit.ly/CRA-PWA
|
||||
serviceWorker.unregister();
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
@ -0,0 +1,56 @@
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Grid, Slider, Typography } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import SubCard from 'ui-component/cards/SubCard';
|
||||
|
||||
// concat 'px'
|
||||
function valueText(value) {
|
||||
return `${value}px`;
|
||||
}
|
||||
|
||||
const BorderRadius = () => {
|
||||
const theme = useTheme();
|
||||
const { borderRadius, onChangeBorderRadius } = useConfig();
|
||||
|
||||
return (
|
||||
<SubCard title="Border Radius">
|
||||
<Grid item xs={12} container spacing={2} alignItems="center" sx={{ mt: 2.5 }}>
|
||||
<Grid item>
|
||||
<Typography variant="h6" color="secondary">
|
||||
4px
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs>
|
||||
<Slider
|
||||
size="small"
|
||||
value={borderRadius}
|
||||
onChange={onChangeBorderRadius}
|
||||
getAriaValueText={valueText}
|
||||
valueLabelDisplay="on"
|
||||
aria-labelledby="discrete-slider-small-steps"
|
||||
marks
|
||||
step={2}
|
||||
min={4}
|
||||
max={24}
|
||||
color="secondary"
|
||||
sx={{
|
||||
'& .MuiSlider-valueLabel': {
|
||||
color: theme.palette.mode === 'dark' ? 'secondary.dark' : 'secondary.light'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="h6" color="secondary">
|
||||
24px
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</SubCard>
|
||||
);
|
||||
};
|
||||
|
||||
export default BorderRadius;
|
@ -0,0 +1,25 @@
|
||||
// material-ui
|
||||
import { FormControl, FormControlLabel, Switch } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import SubCard from 'ui-component/cards/SubCard';
|
||||
|
||||
const BoxContainer = () => {
|
||||
const { container, onChangeContainer } = useConfig();
|
||||
|
||||
return (
|
||||
<SubCard title="Box Container">
|
||||
<FormControl component="fieldset" sx={{ mt: 2 }}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch checked={container} onChange={() => onChangeContainer()} inputProps={{ 'aria-label': 'controlled-direction' }} />
|
||||
}
|
||||
label="Container"
|
||||
/>
|
||||
</FormControl>
|
||||
</SubCard>
|
||||
);
|
||||
};
|
||||
|
||||
export default BoxContainer;
|
@ -0,0 +1,74 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { FormControl, FormControlLabel, Radio, RadioGroup } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import SubCard from 'ui-component/cards/SubCard';
|
||||
|
||||
const FontFamily = () => {
|
||||
const theme = useTheme();
|
||||
const { fontFamily, onChangeFontFamily } = useConfig();
|
||||
|
||||
let initialFont;
|
||||
switch (fontFamily) {
|
||||
case `'Inter', sans-serif`:
|
||||
initialFont = 'Inter';
|
||||
break;
|
||||
case `'Poppins', sans-serif`:
|
||||
initialFont = 'Poppins';
|
||||
break;
|
||||
case `'Roboto', sans-serif`:
|
||||
default:
|
||||
initialFont = 'Roboto';
|
||||
break;
|
||||
}
|
||||
|
||||
// state - font family
|
||||
const [font, setFont] = useState(initialFont);
|
||||
|
||||
const handleFont = (event) => {
|
||||
setFont(event.target.value);
|
||||
onChangeFontFamily(event.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<SubCard title="Font Family">
|
||||
<FormControl>
|
||||
<RadioGroup aria-label="font-family" value={font} onChange={handleFont} name="row-radio-buttons-group">
|
||||
<FormControlLabel
|
||||
value="Roboto"
|
||||
control={<Radio />}
|
||||
label="Roboto"
|
||||
sx={{
|
||||
'& .MuiSvgIcon-root': { fontSize: 28 },
|
||||
'& .MuiFormControlLabel-label': { color: theme.palette.grey[900] }
|
||||
}}
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="Poppins"
|
||||
control={<Radio />}
|
||||
label="Poppins"
|
||||
sx={{
|
||||
'& .MuiSvgIcon-root': { fontSize: 28 },
|
||||
'& .MuiFormControlLabel-label': { color: theme.palette.grey[900] }
|
||||
}}
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="Inter"
|
||||
control={<Radio />}
|
||||
label="Inter"
|
||||
sx={{
|
||||
'& .MuiSvgIcon-root': { fontSize: 28 },
|
||||
'& .MuiFormControlLabel-label': { color: theme.palette.grey[900] }
|
||||
}}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</SubCard>
|
||||
);
|
||||
};
|
||||
|
||||
export default FontFamily;
|
@ -0,0 +1,29 @@
|
||||
// material-ui
|
||||
import { Grid, Stack, Switch, TextField } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import SubCard from 'ui-component/cards/SubCard';
|
||||
|
||||
const InputFilled = () => {
|
||||
const { outlinedFilled, onChangeOutlinedField } = useConfig();
|
||||
|
||||
return (
|
||||
<SubCard title="Input Outlined With Filled">
|
||||
<Grid item xs={12} container spacing={2} alignItems="center">
|
||||
<Grid item>
|
||||
<Stack spacing={2}>
|
||||
<Switch
|
||||
checked={outlinedFilled}
|
||||
onChange={(event) => onChangeOutlinedField(event.target.checked)}
|
||||
inputProps={{ 'aria-label': 'controlled' }}
|
||||
/>
|
||||
<TextField fullWidth id="outlined-basic" label={outlinedFilled ? 'With Background' : 'Without Background'} />
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</SubCard>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputFilled;
|
@ -0,0 +1,61 @@
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { FormControl, FormControlLabel, FormLabel, Radio, RadioGroup, Switch } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import SubCard from 'ui-component/cards/SubCard';
|
||||
|
||||
const Layout = () => {
|
||||
const theme = useTheme();
|
||||
const { navType, rtlLayout, onChangeMenuType, onChangeRTL } = useConfig();
|
||||
|
||||
return (
|
||||
<SubCard title="Layout">
|
||||
<FormControl component="fieldset">
|
||||
<FormLabel component="legend">Mode</FormLabel>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-label="layout"
|
||||
value={navType}
|
||||
onChange={(e) => onChangeMenuType(e.target.value)}
|
||||
name="row-radio-buttons-group"
|
||||
>
|
||||
<FormControlLabel
|
||||
value="light"
|
||||
control={<Radio />}
|
||||
label="Light"
|
||||
sx={{
|
||||
'& .MuiSvgIcon-root': { fontSize: 28 },
|
||||
'& .MuiFormControlLabel-label': { color: theme.palette.grey[900] }
|
||||
}}
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="dark"
|
||||
control={<Radio />}
|
||||
label="Dark"
|
||||
sx={{
|
||||
'& .MuiSvgIcon-root': { fontSize: 28 },
|
||||
'& .MuiFormControlLabel-label': { color: theme.palette.grey[900] }
|
||||
}}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
<FormControl component="fieldset" sx={{ mt: 2 }}>
|
||||
<FormLabel component="legend">Direction</FormLabel>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={rtlLayout}
|
||||
onChange={(event) => onChangeRTL(event.target.checked)}
|
||||
inputProps={{ 'aria-label': 'controlled-direction' }}
|
||||
/>
|
||||
}
|
||||
label="RTL"
|
||||
/>
|
||||
</FormControl>
|
||||
</SubCard>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
@ -0,0 +1,101 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Avatar, Grid } from '@mui/material';
|
||||
import { IconChecks } from '@tabler/icons';
|
||||
|
||||
// project imports
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import SubCard from 'ui-component/cards/SubCard';
|
||||
|
||||
// color import
|
||||
import colors from 'assets/scss/_themes-vars.module.scss';
|
||||
import theme1 from 'assets/scss/_theme1.module.scss';
|
||||
import theme2 from 'assets/scss/_theme2.module.scss';
|
||||
import theme3 from 'assets/scss/_theme3.module.scss';
|
||||
import theme4 from 'assets/scss/_theme4.module.scss';
|
||||
import theme5 from 'assets/scss/_theme5.module.scss';
|
||||
import theme6 from 'assets/scss/_theme6.module.scss';
|
||||
|
||||
const PresetColorBox = ({ color, presetColor, setPresetColor }) => (
|
||||
<Grid item>
|
||||
<Avatar
|
||||
variant="rounded"
|
||||
color="inherit"
|
||||
sx={{
|
||||
background: `linear-gradient(135deg, ${color.primary} 50%, ${color.secondary} 50%)`,
|
||||
opacity: presetColor === color.id ? 0.6 : 1,
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={() => setPresetColor(color?.id)}
|
||||
>
|
||||
{presetColor === color.id && <IconChecks color="#fff" />}
|
||||
</Avatar>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
PresetColorBox.propTypes = {
|
||||
color: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
primary: PropTypes.string,
|
||||
secondary: PropTypes.string
|
||||
}),
|
||||
presetColor: PropTypes.string,
|
||||
setPresetColor: PropTypes.func
|
||||
};
|
||||
|
||||
const PresetColor = () => {
|
||||
const theme = useTheme();
|
||||
const { presetColor, onChangePresetColor } = useConfig();
|
||||
|
||||
const colorOptions = [
|
||||
{
|
||||
id: 'default',
|
||||
primary: theme.palette.mode === 'dark' ? colors.darkPrimaryMain : colors.primaryMain,
|
||||
secondary: theme.palette.mode === 'dark' ? colors.darkSecondaryMain : colors.secondaryMain
|
||||
},
|
||||
{
|
||||
id: 'theme1',
|
||||
primary: theme.palette.mode === 'dark' ? theme1.darkPrimaryMain : theme1.primaryMain,
|
||||
secondary: theme.palette.mode === 'dark' ? theme1.darkSecondaryMain : theme1.secondaryMain
|
||||
},
|
||||
{
|
||||
id: 'theme2',
|
||||
primary: theme.palette.mode === 'dark' ? theme2.darkPrimaryMain : theme2.primaryMain,
|
||||
secondary: theme.palette.mode === 'dark' ? theme2.darkSecondaryMain : theme2.secondaryMain
|
||||
},
|
||||
{
|
||||
id: 'theme3',
|
||||
primary: theme.palette.mode === 'dark' ? theme3.darkPrimaryMain : theme3.primaryMain,
|
||||
secondary: theme.palette.mode === 'dark' ? theme3.darkSecondaryMain : theme3.secondaryMain
|
||||
},
|
||||
{
|
||||
id: 'theme4',
|
||||
primary: theme.palette.mode === 'dark' ? theme4.darkPrimaryMain : theme4.primaryMain,
|
||||
secondary: theme.palette.mode === 'dark' ? theme4.darkSecondaryMain : theme4.secondaryMain
|
||||
},
|
||||
{
|
||||
id: 'theme5',
|
||||
primary: theme.palette.mode === 'dark' ? theme5.darkPrimaryMain : theme5.primaryMain,
|
||||
secondary: theme.palette.mode === 'dark' ? theme5.darkSecondaryMain : theme5.secondaryMain
|
||||
},
|
||||
{
|
||||
id: 'theme6',
|
||||
primary: theme.palette.mode === 'dark' ? theme6.darkPrimaryMain : theme6.primaryMain,
|
||||
secondary: theme.palette.mode === 'dark' ? theme6.darkSecondaryMain : theme6.secondaryMain
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<SubCard title="Preset Color">
|
||||
<Grid item container spacing={2} alignItems="center">
|
||||
{colorOptions.map((color, index) => (
|
||||
<PresetColorBox key={index} color={color} presetColor={presetColor} setPresetColor={onChangePresetColor} />
|
||||
))}
|
||||
</Grid>
|
||||
</SubCard>
|
||||
);
|
||||
};
|
||||
|
||||
export default PresetColor;
|
@ -0,0 +1,108 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Drawer, Fab, Grid, IconButton, Tooltip } from '@mui/material';
|
||||
import { IconSettings } from '@tabler/icons';
|
||||
|
||||
// third-party
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar';
|
||||
|
||||
// project imports
|
||||
import BorderRadius from './BorderRadius';
|
||||
import Layout from './Layout';
|
||||
import PresetColor from './PresetColor';
|
||||
import FontFamily from './FontFamily';
|
||||
import InputFilled from './InputFilled';
|
||||
import BoxContainer from './BoxContainer';
|
||||
import AnimateButton from 'ui-component/extended/AnimateButton';
|
||||
import { gridSpacing } from 'store/constant';
|
||||
|
||||
// ==============================|| LIVE CUSTOMIZATION ||============================== //
|
||||
|
||||
const Customization = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
// drawer on/off
|
||||
const [open, setOpen] = useState(false);
|
||||
const handleToggle = () => {
|
||||
setOpen(!open);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* toggle button */}
|
||||
<Tooltip title="Live Customize">
|
||||
<Fab
|
||||
component="div"
|
||||
onClick={handleToggle}
|
||||
size="medium"
|
||||
variant="circular"
|
||||
color="secondary"
|
||||
sx={{
|
||||
borderRadius: 0,
|
||||
borderTopLeftRadius: '50%',
|
||||
borderBottomLeftRadius: '50%',
|
||||
borderTopRightRadius: '50%',
|
||||
borderBottomRightRadius: '4px',
|
||||
top: '25%',
|
||||
position: 'fixed',
|
||||
right: 10,
|
||||
zIndex: theme.zIndex.speedDial,
|
||||
boxShadow: theme.customShadows.secondary
|
||||
}}
|
||||
>
|
||||
<AnimateButton type="rotate">
|
||||
<IconButton color="inherit" size="large" disableRipple>
|
||||
<IconSettings />
|
||||
</IconButton>
|
||||
</AnimateButton>
|
||||
</Fab>
|
||||
</Tooltip>
|
||||
|
||||
<Drawer
|
||||
anchor="right"
|
||||
onClose={handleToggle}
|
||||
open={open}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
width: 280
|
||||
}
|
||||
}}
|
||||
>
|
||||
{open && (
|
||||
<PerfectScrollbar component="div">
|
||||
<Grid container spacing={gridSpacing} sx={{ p: 3 }}>
|
||||
<Grid item xs={12}>
|
||||
{/* layout type */}
|
||||
<Layout />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{/* Theme Preset Color */}
|
||||
<PresetColor />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{/* font family */}
|
||||
<FontFamily />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{/* border radius */}
|
||||
<BorderRadius />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{/* filled with outline textfield */}
|
||||
<InputFilled />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{/* box container */}
|
||||
<BoxContainer />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</PerfectScrollbar>
|
||||
)}
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Customization;
|
@ -0,0 +1,203 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
ClickAwayListener,
|
||||
Grid,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemText,
|
||||
Paper,
|
||||
Popper,
|
||||
Typography,
|
||||
useMediaQuery
|
||||
} from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import Transitions from 'ui-component/extended/Transitions';
|
||||
|
||||
// assets
|
||||
import TranslateTwoToneIcon from '@mui/icons-material/TranslateTwoTone';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
|
||||
// ==============================|| LOCALIZATION ||============================== //
|
||||
|
||||
const LocalizationSection = () => {
|
||||
const { borderRadius, locale, onChangeLocale } = useConfig();
|
||||
|
||||
const theme = useTheme();
|
||||
const matchesXs = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const anchorRef = useRef(null);
|
||||
const [language, setLanguage] = useState(locale);
|
||||
|
||||
const handleListItemClick = (event, lng) => {
|
||||
setLanguage(lng);
|
||||
onChangeLocale(lng);
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const handleToggle = () => {
|
||||
setOpen((prevOpen) => !prevOpen);
|
||||
};
|
||||
|
||||
const handleClose = (event) => {
|
||||
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const prevOpen = useRef(open);
|
||||
useEffect(() => {
|
||||
if (prevOpen.current === true && open === false) {
|
||||
anchorRef.current.focus();
|
||||
}
|
||||
prevOpen.current = open;
|
||||
}, [open]);
|
||||
|
||||
useEffect(() => {
|
||||
setLanguage(locale);
|
||||
}, [locale]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
ml: 2,
|
||||
[theme.breakpoints.down('md')]: {
|
||||
ml: 1
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
variant="rounded"
|
||||
sx={{
|
||||
...theme.typography.commonAvatar,
|
||||
...theme.typography.mediumAvatar,
|
||||
border: '1px solid',
|
||||
borderColor: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.primary.light,
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.primary.light,
|
||||
color: theme.palette.primary.dark,
|
||||
transition: 'all .2s ease-in-out',
|
||||
'&[aria-controls="menu-list-grow"],&:hover': {
|
||||
borderColor: theme.palette.primary.main,
|
||||
background: theme.palette.primary.main,
|
||||
color: theme.palette.primary.light
|
||||
}
|
||||
}}
|
||||
ref={anchorRef}
|
||||
aria-controls={open ? 'menu-list-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
onClick={handleToggle}
|
||||
color="inherit"
|
||||
>
|
||||
{language !== 'en' && (
|
||||
<Typography variant="h5" sx={{ textTransform: 'uppercase' }} color="inherit">
|
||||
{language}
|
||||
</Typography>
|
||||
)}
|
||||
{language === 'en' && <TranslateTwoToneIcon sx={{ fontSize: '1.3rem' }} />}
|
||||
</Avatar>
|
||||
</Box>
|
||||
|
||||
<Popper
|
||||
placement={matchesXs ? 'bottom-start' : 'bottom'}
|
||||
open={open}
|
||||
anchorEl={anchorRef.current}
|
||||
role={undefined}
|
||||
transition
|
||||
disablePortal
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [matchesXs ? 0 : 0, 20]
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<Transitions position={matchesXs ? 'top-left' : 'top'} in={open} {...TransitionProps}>
|
||||
<Paper elevation={16}>
|
||||
{open && (
|
||||
<List
|
||||
component="nav"
|
||||
sx={{
|
||||
width: '100%',
|
||||
minWidth: 200,
|
||||
maxWidth: 280,
|
||||
bgcolor: theme.palette.background.paper,
|
||||
borderRadius: `${borderRadius}px`,
|
||||
[theme.breakpoints.down('md')]: {
|
||||
maxWidth: 250
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ListItemButton selected={language === 'en'} onClick={(event) => handleListItemClick(event, 'en')}>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Grid container>
|
||||
<Typography color="textPrimary">English</Typography>
|
||||
<Typography variant="caption" color="textSecondary" sx={{ ml: '8px' }}>
|
||||
(UK)
|
||||
</Typography>
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
<ListItemButton selected={language === 'fr'} onClick={(event) => handleListItemClick(event, 'fr')}>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Grid container>
|
||||
<Typography color="textPrimary">français</Typography>
|
||||
<Typography variant="caption" color="textSecondary" sx={{ ml: '8px' }}>
|
||||
(French)
|
||||
</Typography>
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
<ListItemButton selected={language === 'ro'} onClick={(event) => handleListItemClick(event, 'ro')}>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Grid container>
|
||||
<Typography color="textPrimary">Română</Typography>
|
||||
<Typography variant="caption" color="textSecondary" sx={{ ml: '8px' }}>
|
||||
(Romanian)
|
||||
</Typography>
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
<ListItemButton selected={language === 'zh'} onClick={(event) => handleListItemClick(event, 'zh')}>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Grid container>
|
||||
<Typography color="textPrimary">中国人</Typography>
|
||||
<Typography variant="caption" color="textSecondary" sx={{ ml: '8px' }}>
|
||||
(Chinese)
|
||||
</Typography>
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</List>
|
||||
)}
|
||||
</Paper>
|
||||
</Transitions>
|
||||
</ClickAwayListener>
|
||||
)}
|
||||
</Popper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LocalizationSection;
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,279 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
useMediaQuery,
|
||||
Avatar,
|
||||
ClickAwayListener,
|
||||
Grid,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListSubheader,
|
||||
ListItemText,
|
||||
Paper,
|
||||
Popper,
|
||||
Typography
|
||||
} from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import Banner from './Banner';
|
||||
import MainCard from 'ui-component/cards/MainCard';
|
||||
import Transitions from 'ui-component/extended/Transitions';
|
||||
|
||||
// assets
|
||||
import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord';
|
||||
import { IconAccessPoint } from '@tabler/icons';
|
||||
import { drawerWidth, gridSpacing } from 'store/constant';
|
||||
|
||||
const HeaderAvatarStyle = styled(Avatar)(({ theme }) => ({
|
||||
...theme.typography.commonAvatar,
|
||||
...theme.typography.mediumAvatar,
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.secondary.light,
|
||||
color: theme.palette.mode === 'dark' ? theme.palette.secondary.main : theme.palette.secondary.dark,
|
||||
'&:hover': {
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.secondary.main : theme.palette.secondary.dark,
|
||||
color: theme.palette.mode === 'dark' ? theme.palette.secondary.light : theme.palette.secondary.light
|
||||
}
|
||||
}));
|
||||
|
||||
// ==============================|| SEARCH INPUT - MEGA MENu||============================== //
|
||||
|
||||
const MegaMenuSection = () => {
|
||||
const theme = useTheme();
|
||||
const matchDownMd = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const anchorRef = useRef(null);
|
||||
|
||||
const handleToggle = () => {
|
||||
setOpen((prevOpen) => !prevOpen);
|
||||
};
|
||||
const handleClose = (event) => {
|
||||
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (matchDownMd && open) setOpen(false);
|
||||
// eslint-disable-next-line
|
||||
}, [matchDownMd]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeaderAvatarStyle
|
||||
variant="rounded"
|
||||
ref={anchorRef}
|
||||
aria-controls={open ? 'menu-list-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
onClick={handleToggle}
|
||||
sx={{ display: { xs: 'none', md: 'flex' } }}
|
||||
>
|
||||
<IconAccessPoint stroke={1.5} size="1.3rem" />
|
||||
</HeaderAvatarStyle>
|
||||
<Popper
|
||||
placement="bottom-end"
|
||||
open={open}
|
||||
anchorEl={anchorRef.current}
|
||||
role={undefined}
|
||||
transition
|
||||
disablePortal
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [150, 20]
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<Transitions in={open} {...TransitionProps}>
|
||||
<Paper
|
||||
sx={{
|
||||
width: {
|
||||
md: `calc(100vw - 100px)`,
|
||||
lg: `calc(100vw - ${drawerWidth + 100}px)`,
|
||||
xl: `calc(100vw - ${drawerWidth + 140}px)`
|
||||
},
|
||||
maxWidth: { xl: 900, md: 764 }
|
||||
}}
|
||||
>
|
||||
{open && (
|
||||
<MainCard
|
||||
border={false}
|
||||
elevation={16}
|
||||
content={false}
|
||||
boxShadow
|
||||
shadow={theme.shadows[16]}
|
||||
sx={{ p: 1, overflow: { xs: 'visible', md: 'hidden' } }}
|
||||
>
|
||||
<Grid container spacing={gridSpacing}>
|
||||
<Grid item md={4}>
|
||||
<Banner />
|
||||
</Grid>
|
||||
<Grid item md={8}>
|
||||
<Grid
|
||||
container
|
||||
spacing={gridSpacing}
|
||||
sx={{
|
||||
pt: 3,
|
||||
'& .MuiListItemButton-root:hover': {
|
||||
background: 'transparent',
|
||||
'& .MuiTypography-root': {
|
||||
color: 'secondary.main'
|
||||
}
|
||||
},
|
||||
'& .MuiListItemIcon-root': {
|
||||
minWidth: 16
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Grid item xs={4}>
|
||||
<List
|
||||
component="nav"
|
||||
aria-labelledby="nested-list-user"
|
||||
subheader={
|
||||
<ListSubheader id="nested-list-user">
|
||||
<Typography variant="subtitle1"> User Quick</Typography>
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Social Profile" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Account Profile" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="User Cards" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="User List" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Contact" />
|
||||
</ListItemButton>
|
||||
</List>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<List
|
||||
component="nav"
|
||||
aria-labelledby="nested-list-application"
|
||||
subheader={
|
||||
<ListSubheader id="nested-list-application">
|
||||
<Typography variant="subtitle1"> Applications </Typography>
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Chat" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Kanban" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Mail" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Calendar" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="E-Commerce" />
|
||||
</ListItemButton>
|
||||
</List>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<List
|
||||
component="nav"
|
||||
aria-labelledby="nested-list-primitives"
|
||||
subheader={
|
||||
<ListSubheader component="div" id="nested-list-primitives">
|
||||
<Typography variant="subtitle1"> Primitives</Typography>
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Colors" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Typography" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Shadows" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Icons" />
|
||||
</ListItemButton>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
<FiberManualRecordIcon sx={{ fontSize: '0.5rem' }} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Elements" />
|
||||
</ListItemButton>
|
||||
</List>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</MainCard>
|
||||
)}
|
||||
</Paper>
|
||||
</Transitions>
|
||||
</ClickAwayListener>
|
||||
)}
|
||||
</Popper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MegaMenuSection;
|
@ -0,0 +1,111 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { AppBar, Box, IconButton, ClickAwayListener, Grid, Paper, Popper, Toolbar, useMediaQuery } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import LocalizationSection from '../LocalizationSection';
|
||||
import Transitions from 'ui-component/extended/Transitions';
|
||||
|
||||
// assets
|
||||
import { IconDotsVertical } from '@tabler/icons';
|
||||
|
||||
// ==============================|| MOBILE HEADER ||============================== //
|
||||
|
||||
const MobileSection = () => {
|
||||
const theme = useTheme();
|
||||
const matchMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
/**
|
||||
* anchorRef is used on different componets and specifying one type leads to other components throwing an error
|
||||
* */
|
||||
const anchorRef = useRef(null);
|
||||
|
||||
const handleToggle = () => {
|
||||
setOpen((prevOpen) => !prevOpen);
|
||||
};
|
||||
|
||||
const handleClose = (event) => {
|
||||
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const prevOpen = useRef(open);
|
||||
useEffect(() => {
|
||||
if (prevOpen.current === true && open === false) {
|
||||
anchorRef.current.focus();
|
||||
}
|
||||
|
||||
prevOpen.current = open;
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box component="span" ref={anchorRef} sx={{ mt: 1, ml: 1 }}>
|
||||
<IconButton
|
||||
sx={{ color: theme.palette.mode === 'dark' ? 'primary.main' : 'inherit', ml: 0.5, cursor: 'pointer' }}
|
||||
onClick={handleToggle}
|
||||
>
|
||||
<IconDotsVertical
|
||||
stroke={1.5}
|
||||
aria-controls={open ? 'menu-list-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
style={{ fontSize: '1.5rem' }}
|
||||
/>
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
||||
<Popper
|
||||
placement="bottom-end"
|
||||
open={open}
|
||||
anchorEl={anchorRef.current}
|
||||
role={undefined}
|
||||
transition
|
||||
disablePortal
|
||||
style={{ width: '100%', zIndex: 1 }}
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, matchMobile ? 30 : 10]
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<Transitions type="zoom" in={open} {...TransitionProps} sx={{ transformOrigin: 'top right' }}>
|
||||
<Paper>
|
||||
{open && (
|
||||
<AppBar
|
||||
color="inherit"
|
||||
sx={{
|
||||
[theme.breakpoints.down('md')]: {
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark[800] : '#fff'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Toolbar sx={{ pt: 2.75, pb: 2.75 }}>
|
||||
<Grid container justifyContent={matchMobile ? 'space-between' : 'flex-end'} alignItems="center">
|
||||
<LocalizationSection />
|
||||
</Grid>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
)}
|
||||
</Paper>
|
||||
</Transitions>
|
||||
</ClickAwayListener>
|
||||
)}
|
||||
</Popper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MobileSection;
|
@ -0,0 +1,282 @@
|
||||
// material-ui
|
||||
import { useTheme, styled } from '@mui/material/styles';
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
Chip,
|
||||
Divider,
|
||||
Grid,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemSecondaryAction,
|
||||
ListItemText,
|
||||
Stack,
|
||||
Typography
|
||||
} from '@mui/material';
|
||||
|
||||
// assets
|
||||
import { IconBrandTelegram, IconBuildingStore, IconMailbox, IconPhoto } from '@tabler/icons';
|
||||
import User1 from 'assets/images/users/user-round.svg';
|
||||
|
||||
// styles
|
||||
const ListItemWrapper = styled('div')(({ theme }) => ({
|
||||
cursor: 'pointer',
|
||||
padding: 16,
|
||||
'&:hover': {
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.primary.light
|
||||
},
|
||||
'& .MuiListItem-root': {
|
||||
padding: 0
|
||||
}
|
||||
}));
|
||||
|
||||
// ==============================|| NOTIFICATION LIST ITEM ||============================== //
|
||||
|
||||
const NotificationList = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
const chipSX = {
|
||||
height: 24,
|
||||
padding: '0 6px'
|
||||
};
|
||||
const chipErrorSX = {
|
||||
...chipSX,
|
||||
color: theme.palette.orange.dark,
|
||||
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.orange.light,
|
||||
marginRight: '5px'
|
||||
};
|
||||
|
||||
const chipWarningSX = {
|
||||
...chipSX,
|
||||
color: theme.palette.warning.dark,
|
||||
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.warning.light
|
||||
};
|
||||
|
||||
const chipSuccessSX = {
|
||||
...chipSX,
|
||||
color: theme.palette.success.dark,
|
||||
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.success.light,
|
||||
height: 28
|
||||
};
|
||||
|
||||
return (
|
||||
<List
|
||||
sx={{
|
||||
width: '100%',
|
||||
maxWidth: 330,
|
||||
py: 0,
|
||||
borderRadius: '10px',
|
||||
[theme.breakpoints.down('md')]: {
|
||||
maxWidth: 300
|
||||
},
|
||||
'& .MuiListItemSecondaryAction-root': {
|
||||
top: 22
|
||||
},
|
||||
'& .MuiDivider-root': {
|
||||
my: 0
|
||||
},
|
||||
'& .list-container': {
|
||||
pl: 7
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ListItemWrapper>
|
||||
<ListItem alignItems="center">
|
||||
<ListItemAvatar>
|
||||
<Avatar alt="John Doe" src={User1} />
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary="John Doe" />
|
||||
<ListItemSecondaryAction>
|
||||
<Grid container justifyContent="flex-end">
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="caption" display="block" gutterBottom>
|
||||
2 min ago
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Grid container direction="column" className="list-container">
|
||||
<Grid item xs={12} sx={{ pb: 2 }}>
|
||||
<Typography variant="subtitle2">It is a long established fact that a reader will be distracted</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<Chip label="Unread" sx={chipErrorSX} />
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Chip label="New" sx={chipWarningSX} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItemWrapper>
|
||||
<Divider />
|
||||
<ListItemWrapper>
|
||||
<ListItem alignItems="center">
|
||||
<ListItemAvatar>
|
||||
<Avatar
|
||||
sx={{
|
||||
color: theme.palette.success.dark,
|
||||
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.success.light,
|
||||
border: theme.palette.mode === 'dark' ? '1px solid' : 'none',
|
||||
borderColor: theme.palette.success.main
|
||||
}}
|
||||
>
|
||||
<IconBuildingStore stroke={1.5} size="1.3rem" />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={<Typography variant="subtitle1">Store Verification Done</Typography>} />
|
||||
<ListItemSecondaryAction>
|
||||
<Grid container justifyContent="flex-end">
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="caption" display="block" gutterBottom>
|
||||
2 min ago
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Grid container direction="column" className="list-container">
|
||||
<Grid item xs={12} sx={{ pb: 2 }}>
|
||||
<Typography variant="subtitle2">We have successfully received your request.</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<Chip label="Unread" sx={chipErrorSX} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItemWrapper>
|
||||
<Divider />
|
||||
<ListItemWrapper>
|
||||
<ListItem alignItems="center">
|
||||
<ListItemAvatar>
|
||||
<Avatar
|
||||
sx={{
|
||||
color: theme.palette.primary.dark,
|
||||
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.primary.light,
|
||||
border: theme.palette.mode === 'dark' ? '1px solid' : 'none',
|
||||
borderColor: theme.palette.primary.main
|
||||
}}
|
||||
>
|
||||
<IconMailbox stroke={1.5} size="1.3rem" />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={<Typography variant="subtitle1">Check Your Mail.</Typography>} />
|
||||
<ListItemSecondaryAction>
|
||||
<Grid container justifyContent="flex-end">
|
||||
<Grid item>
|
||||
<Typography variant="caption" display="block" gutterBottom>
|
||||
2 min ago
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Grid container direction="column" className="list-container">
|
||||
<Grid item xs={12} sx={{ pb: 2 }}>
|
||||
<Typography variant="subtitle2">All done! Now check your inbox as you're in for a sweet treat!</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<Button variant="contained" disableElevation endIcon={<IconBrandTelegram stroke={1.5} size="1.3rem" />}>
|
||||
Mail
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItemWrapper>
|
||||
<Divider />
|
||||
<ListItemWrapper>
|
||||
<ListItem alignItems="center">
|
||||
<ListItemAvatar>
|
||||
<Avatar alt="John Doe" src={User1} />
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={<Typography variant="subtitle1">John Doe</Typography>} />
|
||||
<ListItemSecondaryAction>
|
||||
<Grid container justifyContent="flex-end">
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="caption" display="block" gutterBottom>
|
||||
2 min ago
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Grid container direction="column" className="list-container">
|
||||
<Grid item xs={12} sx={{ pb: 2 }}>
|
||||
<Typography component="span" variant="subtitle2">
|
||||
Uploaded two file on
|
||||
<Typography component="span" variant="h6">
|
||||
21 Jan 2020
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Card
|
||||
sx={{
|
||||
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.secondary.light
|
||||
}}
|
||||
>
|
||||
<CardContent>
|
||||
<Grid container direction="column">
|
||||
<Grid item xs={12}>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<IconPhoto stroke={1.5} size="1.3rem" />
|
||||
<Typography variant="subtitle1">demo.jpg</Typography>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItemWrapper>
|
||||
<Divider />
|
||||
<ListItemWrapper>
|
||||
<ListItem alignItems="center">
|
||||
<ListItemAvatar>
|
||||
<Avatar alt="John Doe" src={User1} />
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={<Typography variant="subtitle1">John Doe</Typography>} />
|
||||
<ListItemSecondaryAction>
|
||||
<Grid container justifyContent="flex-end">
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="caption" display="block" gutterBottom>
|
||||
2 min ago
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Grid container direction="column" className="list-container">
|
||||
<Grid item xs={12} sx={{ pb: 2 }}>
|
||||
<Typography variant="subtitle2">It is a long established fact that a reader will be distracted</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<Chip label="Confirmation of Account." sx={chipSuccessSX} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItemWrapper>
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotificationList;
|
@ -0,0 +1,217 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
CardActions,
|
||||
Chip,
|
||||
ClickAwayListener,
|
||||
Divider,
|
||||
Grid,
|
||||
Paper,
|
||||
Popper,
|
||||
Stack,
|
||||
TextField,
|
||||
Typography,
|
||||
useMediaQuery
|
||||
} from '@mui/material';
|
||||
|
||||
// third-party
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar';
|
||||
|
||||
// project imports
|
||||
import MainCard from 'ui-component/cards/MainCard';
|
||||
import Transitions from 'ui-component/extended/Transitions';
|
||||
import NotificationList from './NotificationList';
|
||||
|
||||
// assets
|
||||
import { IconBell } from '@tabler/icons';
|
||||
|
||||
// notification status options
|
||||
const status = [
|
||||
{
|
||||
value: 'all',
|
||||
label: 'All Notification'
|
||||
},
|
||||
{
|
||||
value: 'new',
|
||||
label: 'New'
|
||||
},
|
||||
{
|
||||
value: 'unread',
|
||||
label: 'Unread'
|
||||
},
|
||||
{
|
||||
value: 'other',
|
||||
label: 'Other'
|
||||
}
|
||||
];
|
||||
|
||||
// ==============================|| NOTIFICATION ||============================== //
|
||||
|
||||
const NotificationSection = () => {
|
||||
const theme = useTheme();
|
||||
const matchesXs = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [value, setValue] = useState('');
|
||||
/**
|
||||
* anchorRef is used on different componets and specifying one type leads to other components throwing an error
|
||||
* */
|
||||
const anchorRef = useRef(null);
|
||||
|
||||
const handleToggle = () => {
|
||||
setOpen((prevOpen) => !prevOpen);
|
||||
};
|
||||
|
||||
const handleClose = (event) => {
|
||||
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const prevOpen = useRef(open);
|
||||
useEffect(() => {
|
||||
if (prevOpen.current === true && open === false) {
|
||||
anchorRef.current.focus();
|
||||
}
|
||||
prevOpen.current = open;
|
||||
}, [open]);
|
||||
|
||||
const handleChange = (event) => setValue(event?.target.value);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
ml: 2,
|
||||
mr: 3,
|
||||
[theme.breakpoints.down('md')]: {
|
||||
mr: 2
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
variant="rounded"
|
||||
sx={{
|
||||
...theme.typography.commonAvatar,
|
||||
...theme.typography.mediumAvatar,
|
||||
transition: 'all .2s ease-in-out',
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.secondary.light,
|
||||
color: theme.palette.mode === 'dark' ? theme.palette.warning.dark : theme.palette.secondary.dark,
|
||||
'&[aria-controls="menu-list-grow"],&:hover': {
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.warning.dark : theme.palette.secondary.dark,
|
||||
color: theme.palette.mode === 'dark' ? theme.palette.grey[800] : theme.palette.secondary.light
|
||||
}
|
||||
}}
|
||||
ref={anchorRef}
|
||||
aria-controls={open ? 'menu-list-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
onClick={handleToggle}
|
||||
color="inherit"
|
||||
>
|
||||
<IconBell stroke={1.5} size="1.3rem" />
|
||||
</Avatar>
|
||||
</Box>
|
||||
|
||||
<Popper
|
||||
placement={matchesXs ? 'bottom' : 'bottom-end'}
|
||||
open={open}
|
||||
anchorEl={anchorRef.current}
|
||||
role={undefined}
|
||||
transition
|
||||
disablePortal
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [matchesXs ? 5 : 0, 20]
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<Transitions position={matchesXs ? 'top' : 'top-right'} in={open} {...TransitionProps}>
|
||||
<Paper>
|
||||
{open && (
|
||||
<MainCard border={false} elevation={16} content={false} boxShadow shadow={theme.shadows[16]}>
|
||||
<Grid container direction="column" spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Grid container alignItems="center" justifyContent="space-between" sx={{ pt: 2, px: 2 }}>
|
||||
<Grid item>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="subtitle1">All Notification</Typography>
|
||||
<Chip
|
||||
size="small"
|
||||
label="01"
|
||||
sx={{
|
||||
color: theme.palette.background.default,
|
||||
bgcolor: theme.palette.warning.dark
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography component={Link} to="#" variant="subtitle2" color="primary">
|
||||
Mark as all read
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<PerfectScrollbar style={{ height: '100%', maxHeight: 'calc(100vh - 205px)', overflowX: 'hidden' }}>
|
||||
<Grid container direction="column" spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Box sx={{ px: 2, pt: 0.25 }}>
|
||||
<TextField
|
||||
id="outlined-select-currency-native"
|
||||
select
|
||||
fullWidth
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
SelectProps={{
|
||||
native: true
|
||||
}}
|
||||
>
|
||||
{status.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</TextField>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={12} p={0}>
|
||||
<Divider sx={{ my: 0 }} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<NotificationList />
|
||||
</PerfectScrollbar>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Divider />
|
||||
<CardActions sx={{ p: 1.25, justifyContent: 'center' }}>
|
||||
<Button size="small" disableElevation>
|
||||
View All
|
||||
</Button>
|
||||
</CardActions>
|
||||
</MainCard>
|
||||
)}
|
||||
</Paper>
|
||||
</Transitions>
|
||||
</ClickAwayListener>
|
||||
)}
|
||||
</Popper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotificationSection;
|
@ -0,0 +1,76 @@
|
||||
// material-ui
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import { Button, Card, CardContent, Grid, Stack, Typography } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import AnimateButton from 'ui-component/extended/AnimateButton';
|
||||
|
||||
// styles
|
||||
const CardStyle = styled(Card)(({ theme }) => ({
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark[800] : theme.palette.warning.light,
|
||||
marginTop: '16px',
|
||||
marginBottom: '16px',
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
'&:after': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
width: '200px',
|
||||
height: '200px',
|
||||
border: '19px solid ',
|
||||
borderColor: theme.palette.mode === 'dark' ? theme.palette.warning.main : theme.palette.warning.main,
|
||||
borderRadius: '50%',
|
||||
top: '65px',
|
||||
right: '-150px'
|
||||
},
|
||||
'&:before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
width: '200px',
|
||||
height: '200px',
|
||||
border: '3px solid ',
|
||||
borderColor: theme.palette.mode === 'dark' ? theme.palette.warning.main : theme.palette.warning.main,
|
||||
borderRadius: '50%',
|
||||
top: '145px',
|
||||
right: '-70px'
|
||||
}
|
||||
}));
|
||||
|
||||
// ==============================|| PROFILE MENU - UPGRADE PLAN CARD ||============================== //
|
||||
|
||||
const UpgradePlanCard = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<CardStyle>
|
||||
<CardContent>
|
||||
<Grid container direction="column" spacing={2}>
|
||||
<Grid item>
|
||||
<Typography variant="h4">Upgrade your plan</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
color={theme.palette.mode === 'dark' ? 'textSecondary' : 'grey.900'}
|
||||
sx={{ opacity: theme.palette.mode === 'dark' ? 1 : 0.6 }}
|
||||
>
|
||||
70% discount for 1 years <br />
|
||||
subscriptions.
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Stack direction="row">
|
||||
<AnimateButton>
|
||||
<Button variant="contained" color="warning" sx={{ boxShadow: 'none' }}>
|
||||
Go Premium
|
||||
</Button>
|
||||
</AnimateButton>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</CardStyle>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpgradePlanCard;
|
@ -0,0 +1,312 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Card,
|
||||
CardContent,
|
||||
Chip,
|
||||
ClickAwayListener,
|
||||
Divider,
|
||||
Grid,
|
||||
InputAdornment,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
OutlinedInput,
|
||||
Paper,
|
||||
Popper,
|
||||
Stack,
|
||||
Switch,
|
||||
Typography
|
||||
} from '@mui/material';
|
||||
|
||||
// third-party
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar';
|
||||
|
||||
// project imports
|
||||
import MainCard from 'ui-component/cards/MainCard';
|
||||
import Transitions from 'ui-component/extended/Transitions';
|
||||
import UpgradePlanCard from './UpgradePlanCard';
|
||||
import useAuth from 'hooks/useAuth';
|
||||
import User1 from 'assets/images/users/user-round.svg';
|
||||
|
||||
// assets
|
||||
import { IconLogout, IconSearch, IconSettings, IconUser } from '@tabler/icons';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
|
||||
// ==============================|| PROFILE MENU ||============================== //
|
||||
|
||||
const ProfileSection = () => {
|
||||
const theme = useTheme();
|
||||
const { borderRadius } = useConfig();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [sdm, setSdm] = useState(true);
|
||||
const [value, setValue] = useState('');
|
||||
const [notification, setNotification] = useState(false);
|
||||
const [selectedIndex, setSelectedIndex] = useState(-1);
|
||||
const { logout, user } = useAuth();
|
||||
const [open, setOpen] = useState(false);
|
||||
/**
|
||||
* anchorRef is used on different components and specifying one type leads to other components throwing an error
|
||||
* */
|
||||
const anchorRef = useRef(null);
|
||||
const handleLogout = async () => {
|
||||
try {
|
||||
await logout();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = (event) => {
|
||||
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
setOpen(false);
|
||||
};
|
||||
const handleListItemClick = (event, index, route = '') => {
|
||||
setSelectedIndex(index);
|
||||
handleClose(event);
|
||||
|
||||
if (route && route !== '') {
|
||||
navigate(route);
|
||||
}
|
||||
};
|
||||
const handleToggle = () => {
|
||||
setOpen((prevOpen) => !prevOpen);
|
||||
};
|
||||
|
||||
const prevOpen = useRef(open);
|
||||
useEffect(() => {
|
||||
if (prevOpen.current === true && open === false) {
|
||||
anchorRef.current.focus();
|
||||
}
|
||||
|
||||
prevOpen.current = open;
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Chip
|
||||
sx={{
|
||||
height: '48px',
|
||||
alignItems: 'center',
|
||||
borderRadius: '27px',
|
||||
transition: 'all .2s ease-in-out',
|
||||
borderColor: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.primary.light,
|
||||
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.primary.light,
|
||||
'&[aria-controls="menu-list-grow"], &:hover': {
|
||||
borderColor: theme.palette.primary.main,
|
||||
background: `${theme.palette.primary.main}!important`,
|
||||
color: theme.palette.primary.light,
|
||||
'& svg': {
|
||||
stroke: theme.palette.primary.light
|
||||
}
|
||||
},
|
||||
'& .MuiChip-label': {
|
||||
lineHeight: 0
|
||||
}
|
||||
}}
|
||||
icon={
|
||||
<Avatar
|
||||
src={User1}
|
||||
sx={{
|
||||
...theme.typography.mediumAvatar,
|
||||
margin: '8px 0 8px 8px !important',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
ref={anchorRef}
|
||||
aria-controls={open ? 'menu-list-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
color="inherit"
|
||||
/>
|
||||
}
|
||||
label={<IconSettings stroke={1.5} size="1.5rem" color={theme.palette.primary.main} />}
|
||||
variant="outlined"
|
||||
ref={anchorRef}
|
||||
aria-controls={open ? 'menu-list-grow' : undefined}
|
||||
aria-haspopup="true"
|
||||
onClick={handleToggle}
|
||||
color="primary"
|
||||
/>
|
||||
|
||||
<Popper
|
||||
placement="bottom"
|
||||
open={open}
|
||||
anchorEl={anchorRef.current}
|
||||
role={undefined}
|
||||
transition
|
||||
disablePortal
|
||||
popperOptions={{
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, 14]
|
||||
}
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<Transitions in={open} {...TransitionProps}>
|
||||
<Paper>
|
||||
{open && (
|
||||
<MainCard border={false} elevation={16} content={false} boxShadow shadow={theme.shadows[16]}>
|
||||
<Box sx={{ p: 2, pb: 0 }}>
|
||||
<Stack>
|
||||
<Stack direction="row" spacing={0.5} alignItems="center">
|
||||
<Typography variant="h4">Good Morning,</Typography>
|
||||
<Typography component="span" variant="h4" sx={{ fontWeight: 400 }}>
|
||||
{user?.name}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Typography variant="subtitle2">Project Admin</Typography>
|
||||
</Stack>
|
||||
<OutlinedInput
|
||||
sx={{ width: '100%', pr: 1, pl: 2, my: 2 }}
|
||||
id="input-search-profile"
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
placeholder="Search profile options"
|
||||
startAdornment={
|
||||
<InputAdornment position="start">
|
||||
<IconSearch stroke={1.5} size="1rem" color={theme.palette.grey[500]} />
|
||||
</InputAdornment>
|
||||
}
|
||||
aria-describedby="search-helper-text"
|
||||
inputProps={{
|
||||
'aria-label': 'weight'
|
||||
}}
|
||||
/>
|
||||
<Divider />
|
||||
</Box>
|
||||
<PerfectScrollbar style={{ height: '100%', maxHeight: 'calc(100vh - 250px)', overflowX: 'hidden' }}>
|
||||
<Box sx={{ p: 2, pt: 0 }}>
|
||||
<UpgradePlanCard />
|
||||
<Divider />
|
||||
<Card
|
||||
sx={{
|
||||
bgcolor: theme.palette.mode === 'dark' ? theme.palette.dark[800] : theme.palette.primary.light,
|
||||
my: 2
|
||||
}}
|
||||
>
|
||||
<CardContent>
|
||||
<Grid container spacing={3} direction="column">
|
||||
<Grid item>
|
||||
<Grid item container alignItems="center" justifyContent="space-between">
|
||||
<Grid item>
|
||||
<Typography variant="subtitle1">Start DND Mode</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Switch
|
||||
color="primary"
|
||||
checked={sdm}
|
||||
onChange={(e) => setSdm(e.target.checked)}
|
||||
name="sdm"
|
||||
size="small"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Grid item container alignItems="center" justifyContent="space-between">
|
||||
<Grid item>
|
||||
<Typography variant="subtitle1">Allow Notifications</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Switch
|
||||
checked={notification}
|
||||
onChange={(e) => setNotification(e.target.checked)}
|
||||
name="sdm"
|
||||
size="small"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Divider />
|
||||
<List
|
||||
component="nav"
|
||||
sx={{
|
||||
width: '100%',
|
||||
maxWidth: 350,
|
||||
minWidth: 300,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: '10px',
|
||||
[theme.breakpoints.down('md')]: {
|
||||
minWidth: '100%'
|
||||
},
|
||||
'& .MuiListItemButton-root': {
|
||||
mt: 0.5
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ListItemButton
|
||||
sx={{ borderRadius: `${borderRadius}px` }}
|
||||
selected={selectedIndex === 0}
|
||||
onClick={(event) => handleListItemClick(event, 0, '/user/account-profile/profile1')}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<IconSettings stroke={1.5} size="1.3rem" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={<Typography variant="body2">Account Settings</Typography>} />
|
||||
</ListItemButton>
|
||||
<ListItemButton
|
||||
sx={{ borderRadius: `${borderRadius}px` }}
|
||||
selected={selectedIndex === 1}
|
||||
onClick={(event) => handleListItemClick(event, 1, '/user/social-profile/posts')}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<IconUser stroke={1.5} size="1.3rem" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Grid container spacing={1} justifyContent="space-between">
|
||||
<Grid item>
|
||||
<Typography variant="body2">Social Profile</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Chip
|
||||
label="02"
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: theme.palette.mode === 'dark' ? theme.palette.dark.dark : theme.palette.warning.dark,
|
||||
color: theme.palette.background.default
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
<ListItemButton sx={{ borderRadius: `${borderRadius}px` }} selected={selectedIndex === 4} onClick={handleLogout}>
|
||||
<ListItemIcon>
|
||||
<IconLogout stroke={1.5} size="1.3rem" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={<Typography variant="body2">Logout</Typography>} />
|
||||
</ListItemButton>
|
||||
</List>
|
||||
</Box>
|
||||
</PerfectScrollbar>
|
||||
</MainCard>
|
||||
)}
|
||||
</Paper>
|
||||
</Transitions>
|
||||
</ClickAwayListener>
|
||||
)}
|
||||
</Popper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfileSection;
|
@ -0,0 +1,184 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme, styled } from '@mui/material/styles';
|
||||
import { Avatar, Box, Card, Grid, InputAdornment, OutlinedInput, Popper } from '@mui/material';
|
||||
|
||||
// third-party
|
||||
import PopupState, { bindPopper, bindToggle } from 'material-ui-popup-state';
|
||||
|
||||
// project imports
|
||||
import Transitions from 'ui-component/extended/Transitions';
|
||||
|
||||
// assets
|
||||
import { IconAdjustmentsHorizontal, IconSearch, IconX } from '@tabler/icons';
|
||||
import { shouldForwardProp } from '@mui/system';
|
||||
|
||||
// styles
|
||||
const PopperStyle = styled(Popper, { shouldForwardProp })(({ theme }) => ({
|
||||
zIndex: 1100,
|
||||
width: '99%',
|
||||
top: '-55px !important',
|
||||
padding: '0 12px',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
padding: '0 10px'
|
||||
}
|
||||
}));
|
||||
|
||||
const OutlineInputStyle = styled(OutlinedInput, { shouldForwardProp })(({ theme }) => ({
|
||||
width: 434,
|
||||
marginLeft: 16,
|
||||
paddingLeft: 16,
|
||||
paddingRight: 16,
|
||||
'& input': {
|
||||
background: 'transparent !important',
|
||||
paddingLeft: '4px !important'
|
||||
},
|
||||
[theme.breakpoints.down('lg')]: {
|
||||
width: 250
|
||||
},
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width: '100%',
|
||||
marginLeft: 4,
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark[800] : '#fff'
|
||||
}
|
||||
}));
|
||||
|
||||
const HeaderAvatarStyle = styled(Avatar, { shouldForwardProp })(({ theme }) => ({
|
||||
...theme.typography.commonAvatar,
|
||||
...theme.typography.mediumAvatar,
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.secondary.light,
|
||||
color: theme.palette.mode === 'dark' ? theme.palette.secondary.main : theme.palette.secondary.dark,
|
||||
'&:hover': {
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.secondary.main : theme.palette.secondary.dark,
|
||||
color: theme.palette.mode === 'dark' ? theme.palette.secondary.light : theme.palette.secondary.light
|
||||
}
|
||||
}));
|
||||
|
||||
// ==============================|| SEARCH INPUT - MOBILE||============================== //
|
||||
|
||||
const MobileSearch = ({ value, setValue, popupState }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<OutlineInputStyle
|
||||
id="input-search-header"
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
placeholder="Search"
|
||||
startAdornment={
|
||||
<InputAdornment position="start">
|
||||
<IconSearch stroke={1.5} size="1rem" color={theme.palette.grey[500]} />
|
||||
</InputAdornment>
|
||||
}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<HeaderAvatarStyle variant="rounded">
|
||||
<IconAdjustmentsHorizontal stroke={1.5} size="1.3rem" />
|
||||
</HeaderAvatarStyle>
|
||||
<Box sx={{ ml: 2 }}>
|
||||
<Avatar
|
||||
variant="rounded"
|
||||
sx={{
|
||||
...theme.typography.commonAvatar,
|
||||
...theme.typography.mediumAvatar,
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.orange.light,
|
||||
color: theme.palette.orange.dark,
|
||||
'&:hover': {
|
||||
background: theme.palette.orange.dark,
|
||||
color: theme.palette.orange.light
|
||||
}
|
||||
}}
|
||||
{...bindToggle(popupState)}
|
||||
>
|
||||
<IconX stroke={1.5} size="1.3rem" />
|
||||
</Avatar>
|
||||
</Box>
|
||||
</InputAdornment>
|
||||
}
|
||||
aria-describedby="search-helper-text"
|
||||
inputProps={{ 'aria-label': 'weight' }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
MobileSearch.propTypes = {
|
||||
value: PropTypes.string,
|
||||
setValue: PropTypes.func,
|
||||
popupState: PopupState
|
||||
};
|
||||
|
||||
// ==============================|| SEARCH INPUT ||============================== //
|
||||
|
||||
const SearchSection = () => {
|
||||
const theme = useTheme();
|
||||
const [value, setValue] = useState('');
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ display: { xs: 'block', md: 'none' } }}>
|
||||
<PopupState variant="popper" popupId="demo-popup-popper">
|
||||
{(popupState) => (
|
||||
<>
|
||||
<Box sx={{ ml: 2 }}>
|
||||
<HeaderAvatarStyle variant="rounded" {...bindToggle(popupState)}>
|
||||
<IconSearch stroke={1.5} size="1.2rem" />
|
||||
</HeaderAvatarStyle>
|
||||
</Box>
|
||||
<PopperStyle {...bindPopper(popupState)} transition>
|
||||
{({ TransitionProps }) => (
|
||||
<>
|
||||
<Transitions type="zoom" {...TransitionProps} sx={{ transformOrigin: 'center left' }}>
|
||||
<Card
|
||||
sx={{
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark[900] : '#fff',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
border: 0,
|
||||
boxShadow: 'none'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Box sx={{ p: 2 }}>
|
||||
<Grid container alignItems="center" justifyContent="space-between">
|
||||
<Grid item xs>
|
||||
<MobileSearch value={value} setValue={setValue} popupState={popupState} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Card>
|
||||
</Transitions>
|
||||
</>
|
||||
)}
|
||||
</PopperStyle>
|
||||
</>
|
||||
)}
|
||||
</PopupState>
|
||||
</Box>
|
||||
<Box sx={{ display: { xs: 'none', md: 'block' } }}>
|
||||
<OutlineInputStyle
|
||||
id="input-search-header"
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
placeholder="Search"
|
||||
startAdornment={
|
||||
<InputAdornment position="start">
|
||||
<IconSearch stroke={1.5} size="1rem" color={theme.palette.grey[500]} />
|
||||
</InputAdornment>
|
||||
}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<HeaderAvatarStyle variant="rounded">
|
||||
<IconAdjustmentsHorizontal stroke={1.5} size="1.3rem" />
|
||||
</HeaderAvatarStyle>
|
||||
</InputAdornment>
|
||||
}
|
||||
aria-describedby="search-helper-text"
|
||||
inputProps={{ 'aria-label': 'weight' }}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchSection;
|
@ -0,0 +1,90 @@
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Avatar, Box } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import LogoSection from '../LogoSection';
|
||||
import SearchSection from './SearchSection';
|
||||
import MobileSection from './MobileSection';
|
||||
import ProfileSection from './ProfileSection';
|
||||
import LocalizationSection from './LocalizationSection';
|
||||
import MegaMenuSection from './MegaMenuSection';
|
||||
import NotificationSection from './NotificationSection';
|
||||
import { useDispatch, useSelector } from 'store';
|
||||
import { openDrawer } from 'store/slices/menu';
|
||||
|
||||
// assets
|
||||
import { IconMenu2 } from '@tabler/icons';
|
||||
|
||||
// ==============================|| MAIN NAVBAR / HEADER ||============================== //
|
||||
|
||||
const Header = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { drawerOpen } = useSelector((state) => state.menu);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* logo & toggler button */}
|
||||
<Box
|
||||
sx={{
|
||||
width: 228,
|
||||
display: 'flex',
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width: 'auto'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Box component="span" sx={{ display: { xs: 'none', md: 'block' }, flexGrow: 1 }}>
|
||||
<LogoSection />
|
||||
</Box>
|
||||
<Avatar
|
||||
variant="rounded"
|
||||
sx={{
|
||||
...theme.typography.commonAvatar,
|
||||
...theme.typography.mediumAvatar,
|
||||
overflow: 'hidden',
|
||||
transition: 'all .2s ease-in-out',
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.secondary.light,
|
||||
color: theme.palette.mode === 'dark' ? theme.palette.secondary.main : theme.palette.secondary.dark,
|
||||
'&:hover': {
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.secondary.main : theme.palette.secondary.dark,
|
||||
color: theme.palette.mode === 'dark' ? theme.palette.secondary.light : theme.palette.secondary.light
|
||||
}
|
||||
}}
|
||||
onClick={() => dispatch(openDrawer(!drawerOpen))}
|
||||
color="inherit"
|
||||
>
|
||||
<IconMenu2 stroke={1.5} size="1.3rem" />
|
||||
</Avatar>
|
||||
</Box>
|
||||
|
||||
{/* header search */}
|
||||
<SearchSection />
|
||||
<Box sx={{ flexGrow: 1 }} />
|
||||
<Box sx={{ flexGrow: 1 }} />
|
||||
|
||||
{/* mega-menu */}
|
||||
<Box sx={{ display: { xs: 'none', sm: 'block' } }}>
|
||||
<MegaMenuSection />
|
||||
</Box>
|
||||
|
||||
{/* live customization & localization */}
|
||||
<Box sx={{ display: { xs: 'none', sm: 'block' } }}>
|
||||
<LocalizationSection />
|
||||
</Box>
|
||||
|
||||
{/* notification & profile */}
|
||||
<NotificationSection />
|
||||
<ProfileSection />
|
||||
|
||||
{/* mobile header */}
|
||||
<Box sx={{ display: { xs: 'block', sm: 'none' } }}>
|
||||
<MobileSection />
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
@ -0,0 +1,18 @@
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { Link } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import { DASHBOARD_PATH } from 'config';
|
||||
import Logo from 'ui-component/Logo';
|
||||
|
||||
// ==============================|| MAIN LOGO ||============================== //
|
||||
|
||||
const LogoSection = () => (
|
||||
<Link component={RouterLink} to={DASHBOARD_PATH}>
|
||||
<Logo />
|
||||
</Link>
|
||||
);
|
||||
|
||||
export default LogoSection;
|
@ -0,0 +1,129 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { memo } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
Avatar,
|
||||
Card,
|
||||
CardContent,
|
||||
Grid,
|
||||
LinearProgress,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemText,
|
||||
Typography,
|
||||
linearProgressClasses
|
||||
} from '@mui/material';
|
||||
|
||||
// assets
|
||||
import TableChartOutlinedIcon from '@mui/icons-material/TableChartOutlined';
|
||||
|
||||
// styles
|
||||
const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
|
||||
height: 10,
|
||||
borderRadius: 30,
|
||||
[`&.${linearProgressClasses.colorPrimary}`]: {
|
||||
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.dark.light : '#fff'
|
||||
},
|
||||
[`& .${linearProgressClasses.bar}`]: {
|
||||
borderRadius: 5,
|
||||
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.primary.dark : theme.palette.primary.main
|
||||
}
|
||||
}));
|
||||
|
||||
const CardStyle = styled(Card)(({ theme }) => ({
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.primary.light,
|
||||
marginBottom: '22px',
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
'&:after': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
width: '157px',
|
||||
height: '157px',
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark.dark : theme.palette.primary[200],
|
||||
borderRadius: '50%',
|
||||
top: '-105px',
|
||||
right: '-96px'
|
||||
}
|
||||
}));
|
||||
|
||||
// ==============================|| PROGRESS BAR WITH LABEL ||============================== //
|
||||
|
||||
function LinearProgressWithLabel({ value, ...others }) {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Grid container direction="column" spacing={1} sx={{ mt: 1.5 }}>
|
||||
<Grid item>
|
||||
<Grid container justifyContent="space-between">
|
||||
<Grid item>
|
||||
<Typography variant="h6" sx={{ color: theme.palette.mode === 'dark' ? theme.palette.dark.light : theme.palette.primary[800] }}>
|
||||
Progress
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="h6" color="inherit">{`${Math.round(value)}%`}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<BorderLinearProgress variant="determinate" value={value} {...others} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
LinearProgressWithLabel.propTypes = {
|
||||
value: PropTypes.number
|
||||
};
|
||||
|
||||
// ==============================|| SIDEBAR - MENU CARD ||============================== //
|
||||
|
||||
const MenuCard = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<CardStyle>
|
||||
<CardContent sx={{ p: 2 }}>
|
||||
<List sx={{ p: 0, m: 0 }}>
|
||||
<ListItem alignItems="flex-start" disableGutters sx={{ p: 0 }}>
|
||||
<ListItemAvatar sx={{ mt: 0 }}>
|
||||
<Avatar
|
||||
variant="rounded"
|
||||
sx={{
|
||||
...theme.typography.commonAvatar,
|
||||
...theme.typography.largeAvatar,
|
||||
color: theme.palette.primary.main,
|
||||
border: theme.palette.mode === 'dark' ? '1px solid' : 'none',
|
||||
borderColor: theme.palette.primary.main,
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark.dark : '#fff',
|
||||
marginRight: '12px'
|
||||
}}
|
||||
>
|
||||
<TableChartOutlinedIcon fontSize="inherit" />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
sx={{ mt: 0 }}
|
||||
primary={
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
sx={{ color: theme.palette.mode === 'dark' ? theme.palette.dark.light : theme.palette.primary[800] }}
|
||||
>
|
||||
Get Extra Space
|
||||
</Typography>
|
||||
}
|
||||
secondary={<Typography variant="caption"> 28/23 GB</Typography>}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
<LinearProgressWithLabel value={80} />
|
||||
</CardContent>
|
||||
</CardStyle>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(MenuCard);
|
@ -0,0 +1,143 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Collapse, List, ListItemButton, ListItemIcon, ListItemText, Typography } from '@mui/material';
|
||||
import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord';
|
||||
|
||||
// project imports
|
||||
import NavItem from '../NavItem';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
|
||||
// assets
|
||||
import { IconChevronDown, IconChevronUp } from '@tabler/icons';
|
||||
|
||||
// ==============================|| SIDEBAR MENU LIST COLLAPSE ITEMS ||============================== //
|
||||
|
||||
const NavCollapse = ({ menu, level }) => {
|
||||
const theme = useTheme();
|
||||
const { borderRadius } = useConfig();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selected, setSelected] = useState(null);
|
||||
|
||||
const handleClick = () => {
|
||||
setOpen(!open);
|
||||
setSelected(!selected ? menu.id : null);
|
||||
};
|
||||
|
||||
const { pathname } = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
const childrens = menu.children ? menu.children : [];
|
||||
childrens.forEach((item) => {
|
||||
if (pathname && pathname.includes('product-details')) {
|
||||
if (item.url && item.url.includes('product-details')) {
|
||||
setOpen(true);
|
||||
}
|
||||
}
|
||||
if (item.url === pathname) {
|
||||
setOpen(true);
|
||||
}
|
||||
});
|
||||
}, [pathname, menu.children]);
|
||||
|
||||
// menu collapse & item
|
||||
const menus = menu.children?.map((item) => {
|
||||
switch (item.type) {
|
||||
case 'collapse':
|
||||
return <NavCollapse key={item.id} menu={item} level={level + 1} />;
|
||||
case 'item':
|
||||
return <NavItem key={item.id} item={item} level={level + 1} />;
|
||||
default:
|
||||
return (
|
||||
<Typography key={item.id} variant="h6" color="error" align="center">
|
||||
Menu Items Error
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const Icon = menu.icon;
|
||||
const menuIcon = menu.icon ? (
|
||||
<Icon strokeWidth={1.5} size="1.3rem" style={{ marginTop: 'auto', marginBottom: 'auto' }} />
|
||||
) : (
|
||||
<FiberManualRecordIcon
|
||||
sx={{
|
||||
width: selected === menu.id ? 8 : 6,
|
||||
height: selected === menu.id ? 8 : 6
|
||||
}}
|
||||
fontSize={level > 0 ? 'inherit' : 'medium'}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ListItemButton
|
||||
sx={{
|
||||
borderRadius: `${borderRadius}px`,
|
||||
mb: 0.5,
|
||||
alignItems: 'flex-start',
|
||||
backgroundColor: level > 1 ? 'transparent !important' : 'inherit',
|
||||
py: level > 1 ? 1 : 1.25,
|
||||
pl: `${level * 24}px`
|
||||
}}
|
||||
selected={selected === menu.id}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<ListItemIcon sx={{ my: 'auto', minWidth: !menu.icon ? 18 : 36 }}>{menuIcon}</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant={selected === menu.id ? 'h5' : 'body1'} color="inherit" sx={{ my: 'auto' }}>
|
||||
{menu.title}
|
||||
</Typography>
|
||||
}
|
||||
secondary={
|
||||
menu.caption && (
|
||||
<Typography variant="caption" sx={{ ...theme.typography.subMenuCaption }} display="block" gutterBottom>
|
||||
{menu.caption}
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
/>
|
||||
{open ? (
|
||||
<IconChevronUp stroke={1.5} size="1rem" style={{ marginTop: 'auto', marginBottom: 'auto' }} />
|
||||
) : (
|
||||
<IconChevronDown stroke={1.5} size="1rem" style={{ marginTop: 'auto', marginBottom: 'auto' }} />
|
||||
)}
|
||||
</ListItemButton>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
{open && (
|
||||
<List
|
||||
component="div"
|
||||
disablePadding
|
||||
sx={{
|
||||
position: 'relative',
|
||||
'&:after': {
|
||||
content: "''",
|
||||
position: 'absolute',
|
||||
left: '32px',
|
||||
top: 0,
|
||||
height: '100%',
|
||||
width: '1px',
|
||||
opacity: theme.palette.mode === 'dark' ? 0.2 : 1,
|
||||
background: theme.palette.mode === 'dark' ? theme.palette.dark.light : theme.palette.primary.light
|
||||
}
|
||||
}}
|
||||
>
|
||||
{menus}
|
||||
</List>
|
||||
)}
|
||||
</Collapse>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
NavCollapse.propTypes = {
|
||||
menu: PropTypes.object,
|
||||
level: PropTypes.number
|
||||
};
|
||||
|
||||
export default NavCollapse;
|
@ -0,0 +1,61 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Divider, List, Typography } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import NavItem from '../NavItem';
|
||||
import NavCollapse from '../NavCollapse';
|
||||
|
||||
// ==============================|| SIDEBAR MENU LIST GROUP ||============================== //
|
||||
|
||||
const NavGroup = ({ item }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
// menu list collapse & items
|
||||
const items = item.children?.map((menu) => {
|
||||
switch (menu.type) {
|
||||
case 'collapse':
|
||||
return <NavCollapse key={menu.id} menu={menu} level={1} />;
|
||||
case 'item':
|
||||
return <NavItem key={menu.id} item={menu} level={1} />;
|
||||
default:
|
||||
return (
|
||||
<Typography key={menu.id} variant="h6" color="error" align="center">
|
||||
Menu Items Error
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<List
|
||||
subheader={
|
||||
item.title && (
|
||||
<Typography variant="caption" sx={{ ...theme.typography.menuCaption }} display="block" gutterBottom>
|
||||
{item.title}
|
||||
{item.caption && (
|
||||
<Typography variant="caption" sx={{ ...theme.typography.subMenuCaption }} display="block" gutterBottom>
|
||||
{item.caption}
|
||||
</Typography>
|
||||
)}
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
>
|
||||
{items}
|
||||
</List>
|
||||
|
||||
{/* group divider */}
|
||||
<Divider sx={{ mt: 0.25, mb: 1.25 }} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
NavGroup.propTypes = {
|
||||
item: PropTypes.object
|
||||
};
|
||||
|
||||
export default NavGroup;
|
@ -0,0 +1,115 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { forwardRef, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Avatar, Chip, ListItemButton, ListItemIcon, ListItemText, Typography, useMediaQuery } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import { useDispatch, useSelector } from 'store';
|
||||
import { activeItem, openDrawer } from 'store/slices/menu';
|
||||
|
||||
// assets
|
||||
import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord';
|
||||
|
||||
// ==============================|| SIDEBAR MENU LIST ITEMS ||============================== //
|
||||
|
||||
const NavItem = ({ item, level }) => {
|
||||
const theme = useTheme();
|
||||
const matchesSM = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
|
||||
const { borderRadius } = useConfig();
|
||||
const dispatch = useDispatch();
|
||||
const { openItem } = useSelector((state) => state.menu);
|
||||
|
||||
const Icon = item?.icon;
|
||||
const itemIcon = item?.icon ? (
|
||||
<Icon stroke={1.5} size="1.3rem" />
|
||||
) : (
|
||||
<FiberManualRecordIcon
|
||||
sx={{
|
||||
width: openItem.findIndex((id) => id === item?.id) > -1 ? 8 : 6,
|
||||
height: openItem.findIndex((id) => id === item?.id) > -1 ? 8 : 6
|
||||
}}
|
||||
fontSize={level > 0 ? 'inherit' : 'medium'}
|
||||
/>
|
||||
);
|
||||
|
||||
let itemTarget = '_self';
|
||||
if (item.target) {
|
||||
itemTarget = '_blank';
|
||||
}
|
||||
|
||||
let listItemProps = { component: forwardRef((props, ref) => <Link ref={ref} {...props} to={item.url} target={itemTarget} />) };
|
||||
if (item?.external) {
|
||||
listItemProps = { component: 'a', href: item.url, target: itemTarget };
|
||||
}
|
||||
|
||||
const itemHandler = (id) => {
|
||||
dispatch(activeItem([id]));
|
||||
if (matchesSM) dispatch(openDrawer(false));
|
||||
};
|
||||
|
||||
// active menu item on page load
|
||||
useEffect(() => {
|
||||
const currentIndex = document.location.pathname
|
||||
.toString()
|
||||
.split('/')
|
||||
.findIndex((id) => id === item.id);
|
||||
if (currentIndex > -1) {
|
||||
dispatch(activeItem([item.id]));
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ListItemButton
|
||||
{...listItemProps}
|
||||
disabled={item.disabled}
|
||||
sx={{
|
||||
borderRadius: `${borderRadius}px`,
|
||||
mb: 0.5,
|
||||
alignItems: 'flex-start',
|
||||
backgroundColor: level > 1 ? 'transparent !important' : 'inherit',
|
||||
py: level > 1 ? 1 : 1.25,
|
||||
pl: `${level * 24}px`
|
||||
}}
|
||||
selected={openItem?.findIndex((id) => id === item.id) > -1}
|
||||
onClick={() => itemHandler(item.id)}
|
||||
>
|
||||
<ListItemIcon sx={{ my: 'auto', minWidth: !item?.icon ? 18 : 36 }}>{itemIcon}</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant={openItem?.findIndex((id) => id === item.id) > -1 ? 'h5' : 'body1'} color="inherit">
|
||||
{item.title}
|
||||
</Typography>
|
||||
}
|
||||
secondary={
|
||||
item.caption && (
|
||||
<Typography variant="caption" sx={{ ...theme.typography.subMenuCaption }} display="block" gutterBottom>
|
||||
{item.caption}
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
/>
|
||||
{item.chip && (
|
||||
<Chip
|
||||
color={item.chip.color}
|
||||
variant={item.chip.variant}
|
||||
size={item.chip.size}
|
||||
label={item.chip.label}
|
||||
avatar={item.chip.avatar && <Avatar>{item.chip.avatar}</Avatar>}
|
||||
/>
|
||||
)}
|
||||
</ListItemButton>
|
||||
);
|
||||
};
|
||||
|
||||
NavItem.propTypes = {
|
||||
item: PropTypes.object,
|
||||
level: PropTypes.number
|
||||
};
|
||||
|
||||
export default NavItem;
|
@ -0,0 +1,29 @@
|
||||
import { memo } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { Typography } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import NavGroup from './NavGroup';
|
||||
import menuItem from 'menu-items';
|
||||
|
||||
// ==============================|| SIDEBAR MENU LIST ||============================== //
|
||||
|
||||
const MenuList = () => {
|
||||
const navItems = menuItem.items.map((item) => {
|
||||
switch (item.type) {
|
||||
case 'group':
|
||||
return <NavGroup key={item.id} item={item} />;
|
||||
default:
|
||||
return (
|
||||
<Typography key={item.id} variant="h6" color="error" align="center">
|
||||
Menu Items Error
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return <>{navItems}</>;
|
||||
};
|
||||
|
||||
export default memo(MenuList);
|
@ -0,0 +1,96 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { memo, useMemo } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Box, Drawer, Stack, useMediaQuery } from '@mui/material';
|
||||
|
||||
// third-party
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar';
|
||||
|
||||
// project imports
|
||||
import MenuList from './MenuList';
|
||||
import LogoSection from '../LogoSection';
|
||||
import MenuCard from './MenuCard';
|
||||
import { openDrawer } from 'store/slices/menu';
|
||||
import { useDispatch, useSelector } from 'store';
|
||||
import { drawerWidth } from 'store/constant';
|
||||
import Chip from 'ui-component/extended/Chip';
|
||||
|
||||
// ==============================|| SIDEBAR DRAWER ||============================== //
|
||||
|
||||
const Sidebar = ({ window }) => {
|
||||
const theme = useTheme();
|
||||
const matchUpMd = useMediaQuery(theme.breakpoints.up('md'));
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { drawerOpen } = useSelector((state) => state.menu);
|
||||
|
||||
const logo = useMemo(
|
||||
() => (
|
||||
<Box sx={{ display: { xs: 'block', md: 'none' } }}>
|
||||
<Box sx={{ display: 'flex', p: 2, mx: 'auto' }}>
|
||||
<LogoSection />
|
||||
</Box>
|
||||
</Box>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
const drawer = useMemo(
|
||||
() => (
|
||||
<PerfectScrollbar
|
||||
component="div"
|
||||
style={{
|
||||
height: !matchUpMd ? 'calc(100vh - 56px)' : 'calc(100vh - 88px)',
|
||||
paddingLeft: '16px',
|
||||
paddingRight: '16px'
|
||||
}}
|
||||
>
|
||||
<MenuList />
|
||||
<MenuCard />
|
||||
<Stack direction="row" justifyContent="center" sx={{ mb: 2 }}>
|
||||
<Chip label={process.env.REACT_APP_VERSION} disabled chipcolor="secondary" size="small" sx={{ cursor: 'pointer' }} />
|
||||
</Stack>
|
||||
</PerfectScrollbar>
|
||||
),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[matchUpMd]
|
||||
);
|
||||
|
||||
const container = window !== undefined ? () => window.document.body : undefined;
|
||||
|
||||
return (
|
||||
<Box component="nav" sx={{ flexShrink: { md: 0 }, width: matchUpMd ? drawerWidth : 'auto' }} aria-label="mailbox folders">
|
||||
<Drawer
|
||||
container={container}
|
||||
variant={matchUpMd ? 'persistent' : 'temporary'}
|
||||
anchor="left"
|
||||
open={drawerOpen}
|
||||
onClose={() => dispatch(openDrawer(!drawerOpen))}
|
||||
sx={{
|
||||
'& .MuiDrawer-paper': {
|
||||
width: drawerWidth,
|
||||
background: theme.palette.background.default,
|
||||
color: theme.palette.text.primary,
|
||||
borderRight: 'none',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
top: '88px'
|
||||
}
|
||||
}
|
||||
}}
|
||||
ModalProps={{ keepMounted: true }}
|
||||
color="inherit"
|
||||
>
|
||||
{drawerOpen && logo}
|
||||
{drawerOpen && drawer}
|
||||
</Drawer>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
Sidebar.propTypes = {
|
||||
window: PropTypes.object
|
||||
};
|
||||
|
||||
export default memo(Sidebar);
|
@ -0,0 +1,129 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import { AppBar, Box, Container, CssBaseline, Toolbar, useMediaQuery } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import Breadcrumbs from 'ui-component/extended/Breadcrumbs';
|
||||
import Header from './Header';
|
||||
import Sidebar from './Sidebar';
|
||||
import navigation from 'menu-items';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import { drawerWidth } from 'store/constant';
|
||||
import { openDrawer } from 'store/slices/menu';
|
||||
import { useDispatch, useSelector } from 'store';
|
||||
|
||||
// assets
|
||||
import { IconChevronRight } from '@tabler/icons';
|
||||
|
||||
// styles
|
||||
const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({
|
||||
...theme.typography.mainContent,
|
||||
...(!open && {
|
||||
borderBottomLeftRadius: 0,
|
||||
borderBottomRightRadius: 0,
|
||||
transition: theme.transitions.create('margin', {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.shorter
|
||||
}),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
marginLeft: -(drawerWidth - 20),
|
||||
width: `calc(100% - ${drawerWidth}px)`
|
||||
},
|
||||
[theme.breakpoints.down('md')]: {
|
||||
marginLeft: '20px',
|
||||
width: `calc(100% - ${drawerWidth}px)`,
|
||||
padding: '16px'
|
||||
},
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
marginLeft: '10px',
|
||||
width: `calc(100% - ${drawerWidth}px)`,
|
||||
padding: '16px',
|
||||
marginRight: '10px'
|
||||
}
|
||||
}),
|
||||
...(open && {
|
||||
transition: theme.transitions.create('margin', {
|
||||
easing: theme.transitions.easing.easeOut,
|
||||
duration: theme.transitions.duration.shorter
|
||||
}),
|
||||
marginLeft: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
borderBottomRightRadius: 0,
|
||||
width: `calc(100% - ${drawerWidth}px)`,
|
||||
[theme.breakpoints.down('md')]: {
|
||||
marginLeft: '20px'
|
||||
},
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
marginLeft: '10px'
|
||||
}
|
||||
})
|
||||
}));
|
||||
|
||||
// ==============================|| MAIN LAYOUT ||============================== //
|
||||
|
||||
const MainLayout = () => {
|
||||
const theme = useTheme();
|
||||
const matchDownMd = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { drawerOpen } = useSelector((state) => state.menu);
|
||||
const { container } = useConfig();
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(openDrawer(!matchDownMd));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [matchDownMd]);
|
||||
|
||||
const header = useMemo(
|
||||
() => (
|
||||
<Toolbar>
|
||||
<Header />
|
||||
</Toolbar>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex' }}>
|
||||
<CssBaseline />
|
||||
{/* header */}
|
||||
<AppBar
|
||||
enableColorOnDark
|
||||
position="fixed"
|
||||
color="inherit"
|
||||
elevation={0}
|
||||
sx={{
|
||||
bgcolor: theme.palette.background.default,
|
||||
transition: drawerOpen ? theme.transitions.create('width') : 'none'
|
||||
}}
|
||||
>
|
||||
{header}
|
||||
</AppBar>
|
||||
|
||||
{/* drawer */}
|
||||
<Sidebar />
|
||||
|
||||
{/* main content */}
|
||||
<Main theme={theme} open={drawerOpen}>
|
||||
{/* breadcrumb */}
|
||||
{container && (
|
||||
<Container maxWidth="lg">
|
||||
<Breadcrumbs separator={IconChevronRight} navigation={navigation} icon title rightAlign />
|
||||
<Outlet />
|
||||
</Container>
|
||||
)}
|
||||
{!container && (
|
||||
<>
|
||||
<Breadcrumbs separator={IconChevronRight} navigation={navigation} icon title rightAlign />
|
||||
<Outlet />
|
||||
</>
|
||||
)}
|
||||
</Main>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainLayout;
|
@ -0,0 +1,11 @@
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
// ==============================|| MINIMAL LAYOUT ||============================== //
|
||||
|
||||
const MinimalLayout = () => (
|
||||
<>
|
||||
<Outlet />
|
||||
</>
|
||||
);
|
||||
|
||||
export default MinimalLayout;
|
@ -0,0 +1,41 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// third-party
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
// ==============================|| ANIMATION FOR CONTENT ||============================== //
|
||||
|
||||
const NavMotion = ({ children }) => {
|
||||
const motionVariants = {
|
||||
initial: {
|
||||
opacity: 0,
|
||||
scale: 0.99
|
||||
},
|
||||
in: {
|
||||
opacity: 1,
|
||||
scale: 1
|
||||
},
|
||||
out: {
|
||||
opacity: 0,
|
||||
scale: 1.01
|
||||
}
|
||||
};
|
||||
|
||||
const motionTransition = {
|
||||
type: 'tween',
|
||||
ease: 'anticipate',
|
||||
duration: 0.4
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div initial="initial" animate="in" exit="out" variants={motionVariants} transition={motionTransition}>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
NavMotion.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default NavMotion;
|
@ -0,0 +1,25 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
// ==============================|| NAVIGATION SCROLL TO TOP ||============================== //
|
||||
|
||||
const NavigationScroll = ({ children }) => {
|
||||
const { pathname } = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}, [pathname]);
|
||||
|
||||
return children || null;
|
||||
};
|
||||
|
||||
NavigationScroll.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default NavigationScroll;
|
@ -0,0 +1,9 @@
|
||||
import other from './other';
|
||||
|
||||
// ==============================|| MENU ITEMS ||============================== //
|
||||
|
||||
const menuItems = {
|
||||
items: [other]
|
||||
};
|
||||
|
||||
export default menuItems;
|
@ -0,0 +1,49 @@
|
||||
// third-party
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
// assets
|
||||
import { IconBrandChrome, IconHelp, IconSitemap } from '@tabler/icons';
|
||||
|
||||
// constant
|
||||
const icons = {
|
||||
IconBrandChrome,
|
||||
IconHelp,
|
||||
IconSitemap
|
||||
};
|
||||
|
||||
// ==============================|| SAMPLE PAGE & DOCUMENTATION MENU ITEMS ||============================== //
|
||||
|
||||
const other = {
|
||||
id: 'sample-docs-roadmap',
|
||||
type: 'group',
|
||||
children: [
|
||||
{
|
||||
id: 'sample-page',
|
||||
title: <FormattedMessage id="sample-page" />,
|
||||
type: 'item',
|
||||
url: '/sample-page',
|
||||
icon: icons.IconBrandChrome,
|
||||
breadcrumbs: false
|
||||
},
|
||||
{
|
||||
id: 'documentation',
|
||||
title: <FormattedMessage id="documentation" />,
|
||||
type: 'item',
|
||||
url: 'https://codedthemes.gitbook.io/berry/',
|
||||
icon: icons.IconHelp,
|
||||
external: true,
|
||||
target: true
|
||||
},
|
||||
{
|
||||
id: 'roadmap',
|
||||
title: <FormattedMessage id="roadmap" />,
|
||||
type: 'item',
|
||||
url: 'https://codedthemes.gitbook.io/berry/roadmap',
|
||||
icon: icons.IconSitemap,
|
||||
external: true,
|
||||
target: true
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default other;
|
@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
@ -0,0 +1,13 @@
|
||||
const reportWebVitals = (onPerfEntry) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
@ -0,0 +1,12 @@
|
||||
// project imports
|
||||
import MinimalLayout from 'layout/MinimalLayout';
|
||||
|
||||
// ==============================|| AUTHENTICATION ROUTING ||============================== //
|
||||
|
||||
const AuthenticationRoutes = {
|
||||
path: '/',
|
||||
element: <MinimalLayout />,
|
||||
children: []
|
||||
};
|
||||
|
||||
export default AuthenticationRoutes;
|
@ -0,0 +1,41 @@
|
||||
import { lazy } from 'react';
|
||||
|
||||
// project imports
|
||||
import GuestGuard from 'utils/route-guard/GuestGuard';
|
||||
import MinimalLayout from 'layout/MinimalLayout';
|
||||
import NavMotion from 'layout/NavMotion';
|
||||
import Loadable from 'ui-component/Loadable';
|
||||
|
||||
// login routing
|
||||
const AuthLogin = Loadable(lazy(() => import('views/pages/authentication/authentication3/Login3')));
|
||||
const AuthRegister = Loadable(lazy(() => import('views/pages/authentication/authentication3/Register3')));
|
||||
const AuthForgotPassword = Loadable(lazy(() => import('views/pages/authentication/authentication3/ForgotPassword3')));
|
||||
|
||||
// ==============================|| AUTH ROUTING ||============================== //
|
||||
|
||||
const LoginRoutes = {
|
||||
path: '/',
|
||||
element: (
|
||||
<NavMotion>
|
||||
<GuestGuard>
|
||||
<MinimalLayout />
|
||||
</GuestGuard>
|
||||
</NavMotion>
|
||||
),
|
||||
children: [
|
||||
{
|
||||
path: '/login',
|
||||
element: <AuthLogin />
|
||||
},
|
||||
{
|
||||
path: '/register',
|
||||
element: <AuthRegister />
|
||||
},
|
||||
{
|
||||
path: '/forgot',
|
||||
element: <AuthForgotPassword />
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default LoginRoutes;
|
@ -0,0 +1,32 @@
|
||||
import { lazy } from 'react';
|
||||
|
||||
// project imports
|
||||
import MainLayout from 'layout/MainLayout';
|
||||
import Loadable from 'ui-component/Loadable';
|
||||
import AuthGuard from 'utils/route-guard/AuthGuard';
|
||||
|
||||
// sample page routing
|
||||
const SamplePage = Loadable(lazy(() => import('views/sample-page')));
|
||||
|
||||
// ==============================|| MAIN ROUTING ||============================== //
|
||||
|
||||
const MainRoutes = {
|
||||
path: '/',
|
||||
element: (
|
||||
<AuthGuard>
|
||||
<MainLayout />
|
||||
</AuthGuard>
|
||||
),
|
||||
children: [
|
||||
{
|
||||
path: '/',
|
||||
element: <SamplePage />
|
||||
},
|
||||
{
|
||||
path: '/sample-page',
|
||||
element: <SamplePage />
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default MainRoutes;
|
@ -0,0 +1,12 @@
|
||||
import { useRoutes } from 'react-router-dom';
|
||||
|
||||
// routes
|
||||
import MainRoutes from './MainRoutes';
|
||||
import LoginRoutes from './LoginRoutes';
|
||||
import AuthenticationRoutes from './AuthenticationRoutes';
|
||||
|
||||
// ==============================|| ROUTING RENDER ||============================== //
|
||||
|
||||
export default function ThemeRoutes() {
|
||||
return useRoutes([MainRoutes, LoginRoutes, AuthenticationRoutes]);
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
// This optional code is used to register a service worker.
|
||||
// register() is not called by default.
|
||||
|
||||
// This lets the app load faster on subsequent visits in production, and gives
|
||||
// it offline capabilities. However, it also means that developers (and users)
|
||||
// will only see deployed updates on subsequent visits to a page, after all the
|
||||
// existing tabs open on the page have been closed, since previously cached
|
||||
// resources are updated in the background.
|
||||
|
||||
// To learn more about the benefits of this model and instructions on how to
|
||||
// opt-in, read https://bit.ly/CRA-PWA
|
||||
|
||||
const isLocalhost = Boolean(
|
||||
window.location.hostname === 'localhost' ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.0/8 are considered localhost for IPv4.
|
||||
window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
|
||||
);
|
||||
|
||||
function registerValidSW(swUrl, config) {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then((registration) => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker == null) {
|
||||
return;
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
console.log('New content is available and will be used when all tabs for this page are closed. See https://bit.ly/CRA-PWA.');
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onUpdate) {
|
||||
config.onUpdate(registration);
|
||||
}
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log('Content is cached for offline use.');
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function checkValidServiceWorker(swUrl, config) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl, {
|
||||
headers: { 'Service-Worker': 'script' }
|
||||
})
|
||||
.then((response) => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (response.status === 404 || (contentType != null && contentType.indexOf('javascript') === -1)) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('No internet connection found. App is running in offline mode.');
|
||||
});
|
||||
}
|
||||
|
||||
export function register(config) {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl, config);
|
||||
|
||||
// Add some additional logging to localhost, pointing developers to the
|
||||
// service worker/PWA documentation.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
console.log('This web app is being served cache-first by a service worker. To learn more, visit https://bit.ly/CRA-PWA');
|
||||
});
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function unregister() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready
|
||||
.then((registration) => {
|
||||
registration.unregister();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error.message);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
// action - state management
|
||||
import { LOGIN, LOGOUT, REGISTER } from './actions';
|
||||
|
||||
// ==============================|| ACCOUNT REDUCER ||============================== //
|
||||
|
||||
const initialState = {
|
||||
isLoggedIn: false,
|
||||
isInitialized: false,
|
||||
user: null
|
||||
};
|
||||
|
||||
const accountReducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case REGISTER: {
|
||||
const { user } = action.payload;
|
||||
return {
|
||||
...state,
|
||||
user
|
||||
};
|
||||
}
|
||||
case LOGIN: {
|
||||
const { user } = action.payload;
|
||||
return {
|
||||
...state,
|
||||
isLoggedIn: true,
|
||||
isInitialized: true,
|
||||
user
|
||||
};
|
||||
}
|
||||
case LOGOUT: {
|
||||
return {
|
||||
...state,
|
||||
isInitialized: true,
|
||||
isLoggedIn: false,
|
||||
user: null
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return { ...state };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default accountReducer;
|
@ -0,0 +1,5 @@
|
||||
// action - account reducer
|
||||
export const LOGIN = 'LOGIN';
|
||||
export const LOGOUT = 'LOGOUT';
|
||||
export const REGISTER = 'REGISTER';
|
||||
export const FIREBASE_STATE_CHANGED = 'FIREBASE_STATE_CHANGED';
|
@ -0,0 +1,4 @@
|
||||
// theme constant
|
||||
export const gridSpacing = 3;
|
||||
export const drawerWidth = 260;
|
||||
export const appDrawerWidth = 320;
|
@ -0,0 +1,24 @@
|
||||
// third-party
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import { useDispatch as useAppDispatch, useSelector as useAppSelector } from 'react-redux';
|
||||
|
||||
import { persistStore } from 'redux-persist';
|
||||
|
||||
// project imports
|
||||
import rootReducer from './reducer';
|
||||
|
||||
// ==============================|| REDUX - MAIN STORE ||============================== //
|
||||
|
||||
const store = configureStore({
|
||||
reducer: rootReducer,
|
||||
middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false, immutableCheck: false })
|
||||
});
|
||||
|
||||
const persister = persistStore(store);
|
||||
|
||||
const { dispatch } = store;
|
||||
|
||||
const useDispatch = () => useAppDispatch();
|
||||
const useSelector = useAppSelector;
|
||||
|
||||
export { store, persister, dispatch, useSelector, useDispatch };
|
@ -0,0 +1,42 @@
|
||||
// third-party
|
||||
import { combineReducers } from 'redux';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
|
||||
// project imports
|
||||
import snackbarReducer from './slices/snackbar';
|
||||
import customerReducer from './slices/customer';
|
||||
import contactReducer from './slices/contact';
|
||||
import productReducer from './slices/product';
|
||||
import chatReducer from './slices/chat';
|
||||
import calendarReducer from './slices/calendar';
|
||||
import mailReducer from './slices/mail';
|
||||
import userReducer from './slices/user';
|
||||
import cartReducer from './slices/cart';
|
||||
import kanbanReducer from './slices/kanban';
|
||||
import menuReducer from './slices/menu';
|
||||
|
||||
// ==============================|| COMBINE REDUCER ||============================== //
|
||||
|
||||
const reducer = combineReducers({
|
||||
snackbar: snackbarReducer,
|
||||
cart: persistReducer(
|
||||
{
|
||||
key: 'cart',
|
||||
storage,
|
||||
keyPrefix: 'berry-'
|
||||
},
|
||||
cartReducer
|
||||
),
|
||||
kanban: kanbanReducer,
|
||||
customer: customerReducer,
|
||||
contact: contactReducer,
|
||||
product: productReducer,
|
||||
chat: chatReducer,
|
||||
calendar: calendarReducer,
|
||||
mail: mailReducer,
|
||||
user: userReducer,
|
||||
menu: menuReducer
|
||||
});
|
||||
|
||||
export default reducer;
|
@ -0,0 +1,93 @@
|
||||
// third-party
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
// project imports
|
||||
import axios from 'utils/axios';
|
||||
import { dispatch } from '../index';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const initialState = {
|
||||
error: null,
|
||||
events: []
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'calendar',
|
||||
initialState,
|
||||
reducers: {
|
||||
// HAS ERROR
|
||||
hasError(state, action) {
|
||||
state.error = action.payload;
|
||||
},
|
||||
|
||||
// GET EVENTS
|
||||
getEventsSuccess(state, action) {
|
||||
state.events = action.payload;
|
||||
},
|
||||
|
||||
// ADD EVENT
|
||||
addEventSuccess(state, action) {
|
||||
state.events = action.payload;
|
||||
},
|
||||
|
||||
// UPDATE EVENT
|
||||
updateEventSuccess(state, action) {
|
||||
state.events = action.payload;
|
||||
},
|
||||
|
||||
// REMOVE EVENT
|
||||
removeEventSuccess(state, action) {
|
||||
state.events = action.payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Reducer
|
||||
export default slice.reducer;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export function getEvents() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/calendar/events');
|
||||
dispatch(slice.actions.getEventsSuccess(response.data.events));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function addEvent(event) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/calendar/events/new', event);
|
||||
dispatch(slice.actions.addEventSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function updateEvent(event) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/calendar/events/update', event);
|
||||
dispatch(slice.actions.updateEventSuccess(response.data.events));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function removeEvent(eventId) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/calendar/events/remove', { eventId });
|
||||
dispatch(slice.actions.removeEventSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,242 @@
|
||||
// third-party
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
// project imports
|
||||
import axios from 'utils/axios';
|
||||
import { dispatch } from '../index';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const initialState = {
|
||||
error: null,
|
||||
checkout: {
|
||||
step: 0,
|
||||
products: [],
|
||||
subtotal: 0,
|
||||
total: 0,
|
||||
discount: 0,
|
||||
shipping: 0,
|
||||
billing: null,
|
||||
payment: {
|
||||
type: 'free',
|
||||
method: 'cod',
|
||||
card: ''
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'cart',
|
||||
initialState,
|
||||
reducers: {
|
||||
// HAS ERROR
|
||||
hasError(state, action) {
|
||||
state.error = action.payload;
|
||||
},
|
||||
|
||||
// ADD PRODUCT
|
||||
addProductSuccess(state, action) {
|
||||
state.checkout.products = action.payload.products;
|
||||
state.checkout.subtotal += action.payload.subtotal;
|
||||
state.checkout.total += action.payload.subtotal;
|
||||
},
|
||||
|
||||
// REMOVE PRODUCT
|
||||
removeProductSuccess(state, action) {
|
||||
state.checkout.products = action.payload.products;
|
||||
state.checkout.subtotal += -action.payload.subtotal;
|
||||
state.checkout.total += -action.payload.subtotal;
|
||||
},
|
||||
|
||||
// UPDATE PRODUCT
|
||||
updateProductSuccess(state, action) {
|
||||
state.checkout.products = action.payload.products;
|
||||
state.checkout.subtotal = state.checkout.subtotal - action.payload.oldSubTotal + action.payload.subtotal;
|
||||
state.checkout.total = state.checkout.total - action.payload.oldSubTotal + action.payload.subtotal;
|
||||
},
|
||||
|
||||
// SET STEP
|
||||
setStepSuccess(state, action) {
|
||||
state.checkout.step = action.payload;
|
||||
},
|
||||
|
||||
// SET NEXT STEP
|
||||
setNextStepSuccess(state) {
|
||||
state.checkout.step += 1;
|
||||
},
|
||||
|
||||
// SET BACK STEP
|
||||
setBackStepSuccess(state) {
|
||||
state.checkout.step -= 1;
|
||||
},
|
||||
|
||||
// SET BILLING ADDRESS
|
||||
setBillingAddressSuccess(state, action) {
|
||||
state.checkout.billing = action.payload.billing;
|
||||
},
|
||||
|
||||
// SET DISCOUNT
|
||||
setDiscountSuccess(state, action) {
|
||||
let difference = 0;
|
||||
if (state.checkout.discount > 0) {
|
||||
difference = state.checkout.discount;
|
||||
}
|
||||
|
||||
state.checkout.discount = action.payload.amount;
|
||||
state.checkout.total = state.checkout.total + difference - action.payload.amount;
|
||||
},
|
||||
|
||||
// SET SHIPPING CHARGE
|
||||
setShippingChargeSuccess(state, action) {
|
||||
state.checkout.shipping = action.payload.shipping;
|
||||
state.checkout.total += action.payload.newShipping;
|
||||
state.checkout.payment = {
|
||||
...state.checkout.payment,
|
||||
type: action.payload.type
|
||||
};
|
||||
},
|
||||
|
||||
// SET PAYMENT METHOD
|
||||
setPaymentMethodSuccess(state, action) {
|
||||
state.checkout.payment = {
|
||||
...state.checkout.payment,
|
||||
method: action.payload.method
|
||||
};
|
||||
},
|
||||
|
||||
// SET PAYMENT CARD
|
||||
setPaymentCardSuccess(state, action) {
|
||||
state.checkout.payment = {
|
||||
...state.checkout.payment,
|
||||
card: action.payload.card
|
||||
};
|
||||
},
|
||||
|
||||
// RESET CART
|
||||
resetCardSuccess(state) {
|
||||
state.checkout = initialState.checkout;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Reducer
|
||||
export default slice.reducer;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export function addProduct(product, products) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/cart/add', { product, products });
|
||||
dispatch(slice.actions.addProductSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function removeProduct(id, products) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/cart/remove', { id, products });
|
||||
dispatch(slice.actions.removeProductSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function updateProduct(id, quantity, products) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/cart/update', { id, quantity, products });
|
||||
dispatch(slice.actions.updateProductSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setStep(step) {
|
||||
return () => {
|
||||
dispatch(slice.actions.setStepSuccess(step));
|
||||
};
|
||||
}
|
||||
|
||||
export function setNextStep() {
|
||||
return () => {
|
||||
dispatch(slice.actions.setNextStepSuccess({}));
|
||||
};
|
||||
}
|
||||
|
||||
export function setBackStep() {
|
||||
return () => {
|
||||
dispatch(slice.actions.setBackStepSuccess({}));
|
||||
};
|
||||
}
|
||||
|
||||
export function setBillingAddress(address) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/cart/billing-address', { address });
|
||||
dispatch(slice.actions.setBillingAddressSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setDiscount(code, total) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/cart/discount', { code, total });
|
||||
dispatch(slice.actions.setDiscountSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setShippingCharge(charge, shipping) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/cart/shipping-charge', { charge, shipping });
|
||||
dispatch(slice.actions.setShippingChargeSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setPaymentMethod(method) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/cart/payment-method', { method });
|
||||
dispatch(slice.actions.setPaymentMethodSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setPaymentCard(card) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/cart/payment-card', { card });
|
||||
dispatch(slice.actions.setPaymentCardSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function resetCart() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/cart/reset');
|
||||
dispatch(slice.actions.resetCardSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
// third-party
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
// project imports
|
||||
import axios from 'utils/axios';
|
||||
import { dispatch } from '../index';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const initialState = {
|
||||
error: null,
|
||||
chats: [],
|
||||
user: {},
|
||||
users: []
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'chat',
|
||||
initialState,
|
||||
reducers: {
|
||||
// HAS ERROR
|
||||
hasError(state, action) {
|
||||
state.error = action.payload;
|
||||
},
|
||||
|
||||
// GET USER
|
||||
getUserSuccess(state, action) {
|
||||
state.user = action.payload;
|
||||
},
|
||||
|
||||
// GET USER CHATS
|
||||
getUserChatsSuccess(state, action) {
|
||||
state.chats = action.payload;
|
||||
},
|
||||
|
||||
// GET USERS
|
||||
getUsersSuccess(state, action) {
|
||||
state.users = action.payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Reducer
|
||||
export default slice.reducer;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export function getUser(id) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/chat/users/id', { id });
|
||||
dispatch(slice.actions.getUserSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getUserChats(user) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/chat/filter', { user });
|
||||
dispatch(slice.actions.getUserChatsSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function insertChat(chat) {
|
||||
return async () => {
|
||||
try {
|
||||
await axios.post('/api/chat/insert', chat);
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getUsers() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/chat/users');
|
||||
dispatch(slice.actions.getUsersSuccess(response.data.users));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
// third-party
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
// project imports
|
||||
import axios from 'utils/axios';
|
||||
import { dispatch } from '../index';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const initialState = {
|
||||
error: null,
|
||||
contacts: []
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'contact',
|
||||
initialState,
|
||||
reducers: {
|
||||
// HAS ERROR
|
||||
hasError(state, action) {
|
||||
state.error = action.payload;
|
||||
},
|
||||
|
||||
// GET CONTACTS
|
||||
getContactsSuccess(state, action) {
|
||||
state.contacts = action.payload;
|
||||
},
|
||||
|
||||
// MODIFY CONTACT
|
||||
modifyContactSuccess(state, action) {
|
||||
state.contacts = action.payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Reducer
|
||||
export default slice.reducer;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export function getContacts() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/contact/list');
|
||||
dispatch(slice.actions.getContactsSuccess(response.data.contacts));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyContact(contact) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/contact/modify', contact);
|
||||
dispatch(slice.actions.modifyContactSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
// third-party
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
// project imports
|
||||
import axios from 'utils/axios';
|
||||
import { dispatch } from '../index';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const initialState = {
|
||||
error: null,
|
||||
customers: [],
|
||||
orders: [],
|
||||
products: [],
|
||||
productreviews: []
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'customer',
|
||||
initialState,
|
||||
reducers: {
|
||||
// HAS ERROR
|
||||
hasError(state, action) {
|
||||
state.error = action.payload;
|
||||
},
|
||||
|
||||
// GET CUSTOMERS
|
||||
getCustomersSuccess(state, action) {
|
||||
state.customers = action.payload;
|
||||
},
|
||||
|
||||
// GET ORDERS
|
||||
getOrdersSuccess(state, action) {
|
||||
state.orders = action.payload;
|
||||
},
|
||||
|
||||
// GET PRODUCTS
|
||||
getProductsSuccess(state, action) {
|
||||
state.products = action.payload;
|
||||
},
|
||||
|
||||
// GET PRODUCT REVIEWS
|
||||
getProductReviewsSuccess(state, action) {
|
||||
state.productreviews = action.payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Reducer
|
||||
export default slice.reducer;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export function getCustomers() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/customer/list');
|
||||
dispatch(slice.actions.getCustomersSuccess(response.data.customers));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getOrders() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/customer/order/list');
|
||||
dispatch(slice.actions.getOrdersSuccess(response.data.orders));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getProducts() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/customer/product/list');
|
||||
dispatch(slice.actions.getProductsSuccess(response.data.products));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getProductReviews() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/customer/product/reviews');
|
||||
dispatch(slice.actions.getProductReviewsSuccess(response.data.productreviews));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,416 @@
|
||||
// third-party
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
// project imports
|
||||
import axios from 'utils/axios';
|
||||
import { dispatch } from '../index';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const initialState = {
|
||||
error: null,
|
||||
columns: [],
|
||||
columnsOrder: [],
|
||||
comments: [],
|
||||
items: [],
|
||||
profiles: [],
|
||||
selectedItem: false,
|
||||
userStory: [],
|
||||
userStoryOrder: []
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'kanban',
|
||||
initialState,
|
||||
reducers: {
|
||||
// HAS ERROR
|
||||
hasError(state, action) {
|
||||
state.error = action.payload;
|
||||
},
|
||||
|
||||
// ADD COLUMN
|
||||
addColumnSuccess(state, action) {
|
||||
state.columns = action.payload.columns;
|
||||
state.columnsOrder = action.payload.columnsOrder;
|
||||
},
|
||||
|
||||
// EDIT COLUMN
|
||||
editColumnSuccess(state, action) {
|
||||
state.columns = action.payload.columns;
|
||||
},
|
||||
|
||||
// UPDATE COLUMN ORDER
|
||||
updateColumnOrderSuccess(state, action) {
|
||||
state.columnsOrder = action.payload.columnsOrder;
|
||||
},
|
||||
|
||||
// DELETE COLUMN
|
||||
deleteColumnSuccess(state, action) {
|
||||
state.columns = action.payload.columns;
|
||||
state.columnsOrder = action.payload.columnsOrder;
|
||||
},
|
||||
|
||||
// ADD ITEM
|
||||
addItemSuccess(state, action) {
|
||||
state.items = action.payload.items;
|
||||
state.columns = action.payload.columns;
|
||||
state.userStory = action.payload.userStory;
|
||||
},
|
||||
|
||||
// EDIT ITEM
|
||||
editItemSuccess(state, action) {
|
||||
state.items = action.payload.items;
|
||||
state.columns = action.payload.columns;
|
||||
state.userStory = action.payload.userStory;
|
||||
},
|
||||
|
||||
// UPDATE COLUMN ITEM ORDER
|
||||
updateColumnItemOrderSuccess(state, action) {
|
||||
state.columns = action.payload.columns;
|
||||
},
|
||||
|
||||
// SELECT ITEM
|
||||
selectItemSuccess(state, action) {
|
||||
state.selectedItem = action.payload.selectedItem;
|
||||
},
|
||||
|
||||
// ADD ITEM COMMENT
|
||||
addItemCommentSuccess(state, action) {
|
||||
state.items = action.payload.items;
|
||||
state.comments = action.payload.comments;
|
||||
},
|
||||
|
||||
// DELETE ITEM
|
||||
deleteItemSuccess(state, action) {
|
||||
state.items = action.payload.items;
|
||||
state.columns = action.payload.columns;
|
||||
state.userStory = action.payload.userStory;
|
||||
},
|
||||
|
||||
// ADD STORY
|
||||
addStorySuccess(state, action) {
|
||||
state.userStory = action.payload.userStory;
|
||||
state.userStoryOrder = action.payload.userStoryOrder;
|
||||
},
|
||||
|
||||
// EDIT STORY
|
||||
editStorySuccess(state, action) {
|
||||
state.userStory = action.payload.userStory;
|
||||
},
|
||||
|
||||
// UPDATE STORY ORDER
|
||||
updateStoryOrderSuccess(state, action) {
|
||||
state.userStoryOrder = action.payload.userStoryOrder;
|
||||
},
|
||||
|
||||
// UPDATE STORY ITEM ORDER
|
||||
updateStoryItemOrderSuccess(state, action) {
|
||||
state.userStory = action.payload.userStory;
|
||||
},
|
||||
|
||||
// ADD STORY COMMENT
|
||||
addStoryCommentSuccess(state, action) {
|
||||
state.userStory = action.payload.userStory;
|
||||
state.comments = action.payload.comments;
|
||||
},
|
||||
|
||||
// DELETE STORY
|
||||
deleteStorySuccess(state, action) {
|
||||
state.userStory = action.payload.userStory;
|
||||
state.userStoryOrder = action.payload.userStoryOrder;
|
||||
},
|
||||
|
||||
// GET COLUMNS
|
||||
getColumnsSuccess(state, action) {
|
||||
state.columns = action.payload;
|
||||
},
|
||||
|
||||
// GET COLUMNS ORDER
|
||||
getColumnsOrderSuccess(state, action) {
|
||||
state.columnsOrder = action.payload;
|
||||
},
|
||||
|
||||
// GET COMMENTS
|
||||
getCommentsSuccess(state, action) {
|
||||
state.comments = action.payload;
|
||||
},
|
||||
|
||||
// GET PROFILES
|
||||
getProfilesSuccess(state, action) {
|
||||
state.profiles = action.payload;
|
||||
},
|
||||
|
||||
// GET ITEMS
|
||||
getItemsSuccess(state, action) {
|
||||
state.items = action.payload;
|
||||
},
|
||||
|
||||
// GET USER STORY
|
||||
getUserStorySuccess(state, action) {
|
||||
state.userStory = action.payload;
|
||||
},
|
||||
|
||||
// GET USER STORY ORDER
|
||||
getUserStoryOrderSuccess(state, action) {
|
||||
state.userStoryOrder = action.payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Reducer
|
||||
export default slice.reducer;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export function getColumns() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/kanban/columns');
|
||||
dispatch(slice.actions.getColumnsSuccess(response.data.columns));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getColumnsOrder() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/kanban/columns-order');
|
||||
dispatch(slice.actions.getColumnsOrderSuccess(response.data.columnsOrder));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getComments() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/kanban/comments');
|
||||
dispatch(slice.actions.getCommentsSuccess(response.data.comments));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getProfiles() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/kanban/profiles');
|
||||
dispatch(slice.actions.getProfilesSuccess(response.data.profiles));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getItems() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/kanban/items');
|
||||
dispatch(slice.actions.getItemsSuccess(response.data.items));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getUserStory() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/kanban/userstory');
|
||||
dispatch(slice.actions.getUserStorySuccess(response.data.userStory));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getUserStoryOrder() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/kanban/userstory-order');
|
||||
dispatch(slice.actions.getUserStoryOrderSuccess(response.data.userStoryOrder));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function addColumn(column, columns, columnsOrder) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/add-column', { column, columns, columnsOrder });
|
||||
dispatch(slice.actions.addColumnSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function editColumn(column, columns) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/edit-column', { column, columns });
|
||||
dispatch(slice.actions.editColumnSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function updateColumnOrder(columnsOrder) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/update-column-order', { columnsOrder });
|
||||
dispatch(slice.actions.updateColumnOrderSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteColumn(columnId, columnsOrder, columns) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/delete-column', { columnId, columnsOrder, columns });
|
||||
dispatch(slice.actions.deleteColumnSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function addItem(columnId, columns, item, items, storyId, userStory) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/add-item', { columnId, columns, item, items, storyId, userStory });
|
||||
dispatch(slice.actions.addItemSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function editItem(columnId, columns, item, items, storyId, userStory) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/edit-item', { items, item, userStory, storyId, columns, columnId });
|
||||
dispatch(slice.actions.editItemSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function updateColumnItemOrder(columns) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/update-item-order', { columns });
|
||||
dispatch(slice.actions.updateColumnItemOrderSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function selectItem(selectedItem) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/select-item', { selectedItem });
|
||||
dispatch(slice.actions.selectItemSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function addItemComment(itemId, comment, items, comments) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/add-item-comment', { items, itemId, comment, comments });
|
||||
dispatch(slice.actions.addItemCommentSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteItem(itemId, items, columns, userStory) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/delete-item', { columns, itemId, userStory, items });
|
||||
dispatch(slice.actions.deleteItemSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function addStory(story, userStory, userStoryOrder) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/add-story', { userStory, story, userStoryOrder });
|
||||
dispatch(slice.actions.addStorySuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function editStory(story, userStory) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/edit-story', { userStory, story });
|
||||
dispatch(slice.actions.editStorySuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function updateStoryOrder(userStoryOrder) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/update-story-order', { userStoryOrder });
|
||||
dispatch(slice.actions.updateStoryOrderSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function updateStoryItemOrder(userStory) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/update-storyitem-order', { userStory });
|
||||
dispatch(slice.actions.updateStoryItemOrderSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function addStoryComment(storyId, comment, comments, userStory) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/add-story-comment', { userStory, storyId, comment, comments });
|
||||
dispatch(slice.actions.addStoryCommentSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteStory(storyId, userStory, userStoryOrder) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/kanban/delete-story', { userStory, storyId, userStoryOrder });
|
||||
dispatch(slice.actions.deleteStorySuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
// third-party
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
// project imports
|
||||
import axios from 'utils/axios';
|
||||
import { dispatch } from '../index';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const initialState = {
|
||||
error: null,
|
||||
mails: [],
|
||||
unreadCount: undefined
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'mail',
|
||||
initialState,
|
||||
reducers: {
|
||||
// HAS ERROR
|
||||
hasError(state, action) {
|
||||
state.error = action.payload;
|
||||
},
|
||||
|
||||
// GET MAILS
|
||||
getMailsSuccess(state, action) {
|
||||
state.mails = action.payload.mails;
|
||||
state.unreadCount = action.payload.unreadCount;
|
||||
},
|
||||
|
||||
// FILTER MAILS
|
||||
filterMailsSuccess(state, action) {
|
||||
state.mails = action.payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Reducer
|
||||
export default slice.reducer;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export function getMails() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/mails/list');
|
||||
dispatch(slice.actions.getMailsSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function filterMails(filter) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/mails/filter', { filter });
|
||||
dispatch(slice.actions.filterMailsSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setImportant(id) {
|
||||
return async () => {
|
||||
try {
|
||||
await axios.post('/api/mails/setImportant', { id });
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setStarred(id) {
|
||||
return async () => {
|
||||
try {
|
||||
await axios.post('/api/mails/setStarred', { id });
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setRead(id) {
|
||||
return async () => {
|
||||
try {
|
||||
await axios.post('/api/mails/setRead', { id });
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
// initial state
|
||||
const initialState = {
|
||||
openItem: ['dashboard'],
|
||||
drawerOpen: false
|
||||
};
|
||||
|
||||
// ==============================|| SLICE - MENU ||============================== //
|
||||
|
||||
const menu = createSlice({
|
||||
name: 'menu',
|
||||
initialState,
|
||||
reducers: {
|
||||
activeItem(state, action) {
|
||||
state.openItem = action.payload;
|
||||
},
|
||||
|
||||
openDrawer(state, action) {
|
||||
state.drawerOpen = action.payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default menu.reducer;
|
||||
|
||||
export const { activeItem, openDrawer } = menu.actions;
|
@ -0,0 +1,161 @@
|
||||
// third-party
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
// project imports
|
||||
import axios from 'utils/axios';
|
||||
import { dispatch } from '../index';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const initialState = {
|
||||
error: null,
|
||||
products: [],
|
||||
product: null,
|
||||
relatedProducts: [],
|
||||
reviews: [],
|
||||
addresses: []
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'product',
|
||||
initialState,
|
||||
reducers: {
|
||||
// HAS ERROR
|
||||
hasError(state, action) {
|
||||
state.error = action.payload;
|
||||
},
|
||||
|
||||
// GET PRODUCTS
|
||||
getProductsSuccess(state, action) {
|
||||
state.products = action.payload;
|
||||
},
|
||||
|
||||
// FILTER PRODUCTS
|
||||
filterProductsSuccess(state, action) {
|
||||
state.products = action.payload;
|
||||
},
|
||||
|
||||
// GET PRODUCT
|
||||
getProductSuccess(state, action) {
|
||||
state.product = action.payload;
|
||||
},
|
||||
|
||||
// GET RELATED PRODUCTS
|
||||
getRelatedProductsSuccess(state, action) {
|
||||
state.relatedProducts = action.payload;
|
||||
},
|
||||
|
||||
// GET PRODUCT REVIEWS
|
||||
getProductReviewsSuccess(state, action) {
|
||||
state.reviews = action.payload;
|
||||
},
|
||||
|
||||
// GET ADDRESSES
|
||||
getAddressesSuccess(state, action) {
|
||||
state.addresses = action.payload;
|
||||
},
|
||||
|
||||
// ADD ADDRESS
|
||||
addAddressSuccess(state, action) {
|
||||
state.addresses = action.payload;
|
||||
},
|
||||
|
||||
// EDIT ADDRESS
|
||||
editAddressSuccess(state, action) {
|
||||
state.addresses = action.payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Reducer
|
||||
export default slice.reducer;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export function getProducts() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/products/list');
|
||||
dispatch(slice.actions.getProductsSuccess(response.data.products));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function filterProducts(filter) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/products/filter', { filter });
|
||||
dispatch(slice.actions.filterProductsSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getProduct(id) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/product/details', { id });
|
||||
dispatch(slice.actions.getProductSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getRelatedProducts(id) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/product/related', { id });
|
||||
dispatch(slice.actions.getRelatedProductsSuccess(response.data));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getProductReviews() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/review/list');
|
||||
dispatch(slice.actions.getProductReviewsSuccess(response.data.productReviews));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getAddresses() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/address/list');
|
||||
dispatch(slice.actions.getAddressesSuccess(response.data.address));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function addAddress(address) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/address/new', address);
|
||||
dispatch(slice.actions.addAddressSuccess(response.data.address));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function editAddress(address) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/address/edit', address);
|
||||
dispatch(slice.actions.editAddressSuccess(response.data.address));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
const initialState = {
|
||||
action: false,
|
||||
open: false,
|
||||
message: 'Note archived',
|
||||
anchorOrigin: {
|
||||
vertical: 'bottom',
|
||||
horizontal: 'right'
|
||||
},
|
||||
variant: 'default',
|
||||
alert: {
|
||||
color: 'primary',
|
||||
variant: 'filled'
|
||||
},
|
||||
transition: 'Fade',
|
||||
close: true,
|
||||
actionButton: false
|
||||
};
|
||||
|
||||
// ==============================|| SLICE - SNACKBAR ||============================== //
|
||||
|
||||
const snackbar = createSlice({
|
||||
name: 'snackbar',
|
||||
initialState,
|
||||
reducers: {
|
||||
openSnackbar(state, action) {
|
||||
const { open, message, anchorOrigin, variant, alert, transition, close, actionButton } = action.payload;
|
||||
|
||||
state.action = !state.action;
|
||||
state.open = open || initialState.open;
|
||||
state.message = message || initialState.message;
|
||||
state.anchorOrigin = anchorOrigin || initialState.anchorOrigin;
|
||||
state.variant = variant || initialState.variant;
|
||||
state.alert = {
|
||||
color: alert?.color || initialState.alert.color,
|
||||
variant: alert?.variant || initialState.alert.variant
|
||||
};
|
||||
state.transition = transition || initialState.transition;
|
||||
state.close = close === false ? close : initialState.close;
|
||||
state.actionButton = actionButton || initialState.actionButton;
|
||||
},
|
||||
|
||||
closeSnackbar(state) {
|
||||
state.open = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default snackbar.reducer;
|
||||
|
||||
export const { closeSnackbar, openSnackbar } = snackbar.actions;
|
@ -0,0 +1,390 @@
|
||||
// third-party
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
// project imports
|
||||
import axios from 'utils/axios';
|
||||
import { dispatch } from '../index';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const initialState = {
|
||||
error: null,
|
||||
usersS1: [],
|
||||
usersS2: [],
|
||||
followers: [],
|
||||
friendRequests: [],
|
||||
friends: [],
|
||||
gallery: [],
|
||||
posts: [],
|
||||
detailCards: [],
|
||||
simpleCards: [],
|
||||
profileCards: []
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'user',
|
||||
initialState,
|
||||
reducers: {
|
||||
// HAS ERROR
|
||||
hasError(state, action) {
|
||||
state.error = action.payload;
|
||||
},
|
||||
|
||||
// GET USERS STYLE 1
|
||||
getUsersListStyle1Success(state, action) {
|
||||
state.usersS1 = action.payload;
|
||||
},
|
||||
|
||||
// GET USERS STYLE 2
|
||||
getUsersListStyle2Success(state, action) {
|
||||
state.usersS2 = action.payload;
|
||||
},
|
||||
|
||||
// GET FOLLOWERS
|
||||
getFollowersSuccess(state, action) {
|
||||
state.followers = action.payload;
|
||||
},
|
||||
|
||||
// FILTER FOLLOWERS
|
||||
filterFollowersSuccess(state, action) {
|
||||
state.followers = action.payload;
|
||||
},
|
||||
|
||||
// GET FRIEND REQUESTS
|
||||
getFriendRequestsSuccess(state, action) {
|
||||
state.friendRequests = action.payload;
|
||||
},
|
||||
|
||||
// FILTER FRIEND REQUESTS
|
||||
filterFriendRequestsSuccess(state, action) {
|
||||
state.friendRequests = action.payload;
|
||||
},
|
||||
|
||||
// GET FRIENDS
|
||||
getFriendsSuccess(state, action) {
|
||||
state.friends = action.payload;
|
||||
},
|
||||
|
||||
// FILTER FRIENDS
|
||||
filterFriendsSuccess(state, action) {
|
||||
state.friends = action.payload;
|
||||
},
|
||||
|
||||
// GET GALLERY
|
||||
getGallerySuccess(state, action) {
|
||||
state.gallery = action.payload;
|
||||
},
|
||||
|
||||
// GET POSTS
|
||||
getPostsSuccess(state, action) {
|
||||
state.posts = action.payload;
|
||||
},
|
||||
|
||||
// EDIT COMMENT
|
||||
editCommentSuccess(state, action) {
|
||||
state.posts = action.payload;
|
||||
},
|
||||
|
||||
// ADD COMMENT
|
||||
addCommentSuccess(state, action) {
|
||||
state.posts = action.payload;
|
||||
},
|
||||
|
||||
// ADD REPLY
|
||||
addReplySuccess(state, action) {
|
||||
state.posts = action.payload;
|
||||
},
|
||||
|
||||
// LIKE POST
|
||||
likePostSuccess(state, action) {
|
||||
state.posts = action.payload;
|
||||
},
|
||||
|
||||
// LIKE COMMENT
|
||||
likeCommentSuccess(state, action) {
|
||||
state.posts = action.payload;
|
||||
},
|
||||
|
||||
// LIKE REPLY
|
||||
likeReplySuccess(state, action) {
|
||||
state.posts = action.payload;
|
||||
},
|
||||
|
||||
// GET DETAIL CARDS
|
||||
getDetailCardsSuccess(state, action) {
|
||||
state.detailCards = action.payload;
|
||||
},
|
||||
|
||||
// FILTER DETAIL CARDS
|
||||
filterDetailCardsSuccess(state, action) {
|
||||
state.detailCards = action.payload;
|
||||
},
|
||||
|
||||
// GET SIMPLE CARDS
|
||||
getSimpleCardsSuccess(state, action) {
|
||||
state.simpleCards = action.payload;
|
||||
},
|
||||
|
||||
// FILTER SIMPLE CARDS
|
||||
filterSimpleCardsSuccess(state, action) {
|
||||
state.simpleCards = action.payload;
|
||||
},
|
||||
|
||||
// GET PROFILE CARDS
|
||||
getProfileCardsSuccess(state, action) {
|
||||
state.profileCards = action.payload;
|
||||
},
|
||||
|
||||
// FILTER PROFILE CARDS
|
||||
filterProfileCardsSuccess(state, action) {
|
||||
state.profileCards = action.payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Reducer
|
||||
export default slice.reducer;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export function getUsersListStyle1() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/user-list/s1/list');
|
||||
dispatch(slice.actions.getUsersListStyle1Success(response.data.users_s1));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getUsersListStyle2() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/user-list/s2/list');
|
||||
dispatch(slice.actions.getUsersListStyle2Success(response.data.users_s2));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getFollowers() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/followers/list');
|
||||
dispatch(slice.actions.getFollowersSuccess(response.data.followers));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function filterFollowers(key) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/followers/filter', { key });
|
||||
dispatch(slice.actions.filterFollowersSuccess(response.data.results));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getFriendRequests() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/friend-request/list');
|
||||
dispatch(slice.actions.getFriendRequestsSuccess(response.data.friends));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function filterFriendRequests(key) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/friend-request/filter', { key });
|
||||
dispatch(slice.actions.filterFriendRequestsSuccess(response.data.results));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getFriends() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/friends/list');
|
||||
dispatch(slice.actions.getFriendsSuccess(response.data.friends));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function filterFriends(key) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/friends/filter', { key });
|
||||
dispatch(slice.actions.filterFriendsSuccess(response.data.results));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getGallery() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/gallery/list');
|
||||
dispatch(slice.actions.getGallerySuccess(response.data.gallery));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getPosts() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/posts/list');
|
||||
dispatch(slice.actions.getPostsSuccess(response.data.posts));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function editComment(key, id) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/posts/editComment', { key, id });
|
||||
dispatch(slice.actions.editCommentSuccess(response.data.posts));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function addComment(postId, comment) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/comments/add', { postId, comment });
|
||||
dispatch(slice.actions.addCommentSuccess(response.data.posts));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function addReply(postId, commentId, reply) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/replies/add', { postId, commentId, reply });
|
||||
dispatch(slice.actions.addReplySuccess(response.data.posts));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function likePost(postId) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/posts/list/like', { postId });
|
||||
dispatch(slice.actions.likePostSuccess(response.data.posts));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function likeComment(postId, commentId) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/comments/list/like', { postId, commentId });
|
||||
dispatch(slice.actions.likeCommentSuccess(response.data.posts));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function likeReply(postId, commentId, replayId) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/replies/list/like', { postId, commentId, replayId });
|
||||
dispatch(slice.actions.likeReplySuccess(response.data.posts));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getDetailCards() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/details-card/list');
|
||||
dispatch(slice.actions.getDetailCardsSuccess(response.data.users));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function filterDetailCards(key) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/details-card/filter', { key });
|
||||
dispatch(slice.actions.filterDetailCardsSuccess(response.data.results));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getSimpleCards() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/simple-card/list');
|
||||
dispatch(slice.actions.getSimpleCardsSuccess(response.data.users));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function filterSimpleCards(key) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/simple-card/filter', { key });
|
||||
dispatch(slice.actions.filterSimpleCardsSuccess(response.data.results));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getProfileCards() {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/profile-card/list');
|
||||
dispatch(slice.actions.getProfileCardsSuccess(response.data.users));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function filterProfileCards(key) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/profile-card/filter', { key });
|
||||
dispatch(slice.actions.filterProfileCardsSuccess(response.data.results));
|
||||
} catch (error) {
|
||||
dispatch(slice.actions.hasError(error));
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,315 @@
|
||||
export default function componentStyleOverrides(theme, borderRadius, outlinedFilled) {
|
||||
const mode = theme.palette.mode;
|
||||
const bgColor = mode === 'dark' ? theme.palette.dark[800] : theme.palette.grey[50];
|
||||
const menuSelectedBack = mode === 'dark' ? theme.palette.secondary.main + 15 : theme.palette.secondary.light;
|
||||
const menuSelected = mode === 'dark' ? theme.palette.secondary.main : theme.palette.secondary.dark;
|
||||
|
||||
return {
|
||||
MuiButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
fontWeight: 500,
|
||||
borderRadius: '4px'
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiPaper: {
|
||||
defaultProps: {
|
||||
elevation: 0
|
||||
},
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundImage: 'none'
|
||||
},
|
||||
rounded: {
|
||||
borderRadius: `${borderRadius}px`
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiCardHeader: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: theme.palette.text.dark,
|
||||
padding: '24px'
|
||||
},
|
||||
title: {
|
||||
fontSize: '1.125rem'
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiCardContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: '24px'
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiCardActions: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: '24px'
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiAlert: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
alignItems: 'center'
|
||||
},
|
||||
outlined: {
|
||||
border: '1px dashed'
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiListItemButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: theme.palette.text.primary,
|
||||
paddingTop: '10px',
|
||||
paddingBottom: '10px',
|
||||
'&.Mui-selected': {
|
||||
color: menuSelected,
|
||||
backgroundColor: menuSelectedBack,
|
||||
'&:hover': {
|
||||
backgroundColor: menuSelectedBack
|
||||
},
|
||||
'& .MuiListItemIcon-root': {
|
||||
color: menuSelected
|
||||
}
|
||||
},
|
||||
'&:hover': {
|
||||
backgroundColor: menuSelectedBack,
|
||||
color: menuSelected,
|
||||
'& .MuiListItemIcon-root': {
|
||||
color: menuSelected
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiListItemIcon: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: theme.palette.text.primary,
|
||||
minWidth: '36px'
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiListItemText: {
|
||||
styleOverrides: {
|
||||
primary: {
|
||||
color: theme.palette.text.dark
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiInputBase: {
|
||||
styleOverrides: {
|
||||
input: {
|
||||
color: theme.palette.text.dark,
|
||||
'&::placeholder': {
|
||||
color: theme.palette.text.secondary,
|
||||
fontSize: '0.875rem'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiOutlinedInput: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
background: outlinedFilled ? bgColor : 'transparent',
|
||||
borderRadius: `${borderRadius}px`,
|
||||
'& .MuiOutlinedInput-notchedOutline': {
|
||||
borderColor: mode === 'dark' ? theme.palette.text.primary + 28 : theme.palette.grey[400]
|
||||
},
|
||||
'&:hover $notchedOutline': {
|
||||
borderColor: theme.palette.primary.light
|
||||
},
|
||||
'&.MuiInputBase-multiline': {
|
||||
padding: 1
|
||||
}
|
||||
},
|
||||
input: {
|
||||
fontWeight: 500,
|
||||
background: outlinedFilled ? bgColor : 'transparent',
|
||||
padding: '15.5px 14px',
|
||||
borderRadius: `${borderRadius}px`,
|
||||
'&.MuiInputBase-inputSizeSmall': {
|
||||
padding: '10px 14px',
|
||||
'&.MuiInputBase-inputAdornedStart': {
|
||||
paddingLeft: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
inputAdornedStart: {
|
||||
paddingLeft: 4
|
||||
},
|
||||
notchedOutline: {
|
||||
borderRadius: `${borderRadius}px`
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiSlider: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.Mui-disabled': {
|
||||
color: mode === 'dark' ? theme.palette.text.primary + 50 : theme.palette.grey[300]
|
||||
}
|
||||
},
|
||||
mark: {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
width: '4px'
|
||||
},
|
||||
valueLabel: {
|
||||
color: mode === 'dark' ? theme.palette.primary.main : theme.palette.primary.light
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiAutocomplete: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiAutocomplete-tag': {
|
||||
background: mode === 'dark' ? theme.palette.text.primary + 20 : theme.palette.secondary.light,
|
||||
borderRadius: 4,
|
||||
color: theme.palette.text.dark,
|
||||
'.MuiChip-deleteIcon': {
|
||||
color: mode === 'dark' ? theme.palette.text.primary + 80 : theme.palette.secondary[200]
|
||||
}
|
||||
}
|
||||
},
|
||||
popper: {
|
||||
borderRadius: `${borderRadius}px`,
|
||||
boxShadow: '0px 8px 10px -5px rgb(0 0 0 / 20%), 0px 16px 24px 2px rgb(0 0 0 / 14%), 0px 6px 30px 5px rgb(0 0 0 / 12%)'
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiDivider: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderColor: theme.palette.divider,
|
||||
opacity: mode === 'dark' ? 0.2 : 1
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiSelect: {
|
||||
styleOverrides: {
|
||||
select: {
|
||||
'&:focus': {
|
||||
backgroundColor: 'transparent'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiCheckbox: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
/** checked not prop
|
||||
*"&.Mui-checked": {
|
||||
* fontSize: "28px"
|
||||
*}
|
||||
*/
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiAvatar: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: mode === 'dark' ? theme.palette.dark.main : theme.palette.primary.dark,
|
||||
background: mode === 'dark' ? theme.palette.text.primary : theme.palette.primary[200]
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiChip: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.MuiChip-deletable .MuiChip-deleteIcon': {
|
||||
color: 'inherit'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiTimelineContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: theme.palette.text.dark,
|
||||
fontSize: '16px'
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiTreeItem: {
|
||||
styleOverrides: {
|
||||
label: {
|
||||
marginTop: 14,
|
||||
marginBottom: 14
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiTimelineDot: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
boxShadow: 'none'
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiInternalDateTimePickerTabs: {
|
||||
styleOverrides: {
|
||||
tabs: {
|
||||
backgroundColor: mode === 'dark' ? theme.palette.dark[900] : theme.palette.primary.light,
|
||||
'& .MuiTabs-flexContainer': {
|
||||
borderColor: mode === 'dark' ? theme.palette.text.primary + 20 : theme.palette.primary[200]
|
||||
},
|
||||
'& .MuiTab-root': {
|
||||
color: mode === 'dark' ? theme.palette.text.secondary : theme.palette.grey[900]
|
||||
},
|
||||
'& .MuiTabs-indicator': {
|
||||
backgroundColor: theme.palette.primary.dark
|
||||
},
|
||||
'& .Mui-selected': {
|
||||
color: theme.palette.primary.dark
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiTabs: {
|
||||
styleOverrides: {
|
||||
flexContainer: {
|
||||
borderBottom: '1px solid',
|
||||
borderColor: mode === 'dark' ? theme.palette.text.primary + 20 : theme.palette.grey[200]
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiDialog: {
|
||||
styleOverrides: {
|
||||
paper: {
|
||||
padding: '12px 0 12px 0'
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiTableCell: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderColor: mode === 'dark' ? theme.palette.text.primary + 15 : theme.palette.grey[200],
|
||||
'&.MuiTableCell-head': {
|
||||
fontSize: '0.875rem',
|
||||
color: theme.palette.grey[600],
|
||||
fontWeight: 500
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiTooltip: {
|
||||
styleOverrides: {
|
||||
tooltip: {
|
||||
color: theme.palette.background.paper,
|
||||
background: theme.palette.text.primary
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiDialogTitle: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
fontSize: '1.25rem'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { CssBaseline, StyledEngineProvider } from '@mui/material';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
|
||||
// project import
|
||||
import useConfig from 'hooks/useConfig';
|
||||
import Palette from './palette';
|
||||
import Typography from './typography';
|
||||
|
||||
import componentStyleOverrides from './compStyleOverride';
|
||||
import customShadows from './shadows';
|
||||
|
||||
export default function ThemeCustomization({ children }) {
|
||||
const { borderRadius, fontFamily, navType, outlinedFilled, presetColor, rtlLayout } = useConfig();
|
||||
|
||||
const theme = useMemo(() => Palette(navType, presetColor), [navType, presetColor]);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const themeTypography = useMemo(() => Typography(theme, borderRadius, fontFamily), [theme, borderRadius, fontFamily]);
|
||||
const themeCustomShadows = useMemo(() => customShadows(navType, theme), [navType, theme]);
|
||||
|
||||
const themeOptions = useMemo(
|
||||
() => ({
|
||||
direction: rtlLayout ? 'rtl' : 'ltr',
|
||||
palette: theme.palette,
|
||||
mixins: {
|
||||
toolbar: {
|
||||
minHeight: '48px',
|
||||
padding: '16px',
|
||||
'@media (min-width: 600px)': {
|
||||
minHeight: '48px'
|
||||
}
|
||||
}
|
||||
},
|
||||
typography: themeTypography,
|
||||
customShadows: themeCustomShadows
|
||||
}),
|
||||
[rtlLayout, theme, themeCustomShadows, themeTypography]
|
||||
);
|
||||
|
||||
const themes = createTheme(themeOptions);
|
||||
themes.components = useMemo(() => componentStyleOverrides(themes, borderRadius, outlinedFilled), [themes, borderRadius, outlinedFilled]);
|
||||
|
||||
return (
|
||||
<StyledEngineProvider injectFirst>
|
||||
<ThemeProvider theme={themes}>
|
||||
<CssBaseline />
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</StyledEngineProvider>
|
||||
);
|
||||
}
|
||||
|
||||
ThemeCustomization.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
@ -0,0 +1,112 @@
|
||||
// material-ui
|
||||
import { createTheme } from '@mui/material/styles';
|
||||
|
||||
// assets
|
||||
import defaultColor from 'assets/scss/_themes-vars.module.scss';
|
||||
import theme1 from 'assets/scss/_theme1.module.scss';
|
||||
import theme2 from 'assets/scss/_theme2.module.scss';
|
||||
import theme3 from 'assets/scss/_theme3.module.scss';
|
||||
import theme4 from 'assets/scss/_theme4.module.scss';
|
||||
import theme5 from 'assets/scss/_theme5.module.scss';
|
||||
import theme6 from 'assets/scss/_theme6.module.scss';
|
||||
|
||||
// ==============================|| DEFAULT THEME - PALETTE ||============================== //
|
||||
|
||||
const Palette = (navType, presetColor) => {
|
||||
let colors;
|
||||
switch (presetColor) {
|
||||
case 'theme1':
|
||||
colors = theme1;
|
||||
break;
|
||||
case 'theme2':
|
||||
colors = theme2;
|
||||
break;
|
||||
case 'theme3':
|
||||
colors = theme3;
|
||||
break;
|
||||
case 'theme4':
|
||||
colors = theme4;
|
||||
break;
|
||||
case 'theme5':
|
||||
colors = theme5;
|
||||
break;
|
||||
case 'theme6':
|
||||
colors = theme6;
|
||||
break;
|
||||
case 'default':
|
||||
default:
|
||||
colors = defaultColor;
|
||||
}
|
||||
|
||||
return createTheme({
|
||||
palette: {
|
||||
mode: navType,
|
||||
common: {
|
||||
black: colors.darkPaper
|
||||
},
|
||||
primary: {
|
||||
light: navType === 'dark' ? colors.darkPrimaryLight : colors.primaryLight,
|
||||
main: navType === 'dark' ? colors.darkPrimaryMain : colors.primaryMain,
|
||||
dark: navType === 'dark' ? colors.darkPrimaryDark : colors.primaryDark,
|
||||
200: navType === 'dark' ? colors.darkPrimary200 : colors.primary200,
|
||||
800: navType === 'dark' ? colors.darkPrimary800 : colors.primary800
|
||||
},
|
||||
secondary: {
|
||||
light: navType === 'dark' ? colors.darkSecondaryLight : colors.secondaryLight,
|
||||
main: navType === 'dark' ? colors.darkSecondaryMain : colors.secondaryMain,
|
||||
dark: navType === 'dark' ? colors.darkSecondaryDark : colors.secondaryDark,
|
||||
200: navType === 'dark' ? colors.darkSecondary200 : colors.secondary200,
|
||||
800: navType === 'dark' ? colors.darkSecondary800 : colors.secondary800
|
||||
},
|
||||
error: {
|
||||
light: colors.errorLight,
|
||||
main: colors.errorMain,
|
||||
dark: colors.errorDark
|
||||
},
|
||||
orange: {
|
||||
light: colors.orangeLight,
|
||||
main: colors.orangeMain,
|
||||
dark: colors.orangeDark
|
||||
},
|
||||
warning: {
|
||||
light: colors.warningLight,
|
||||
main: colors.warningMain,
|
||||
dark: colors.warningDark
|
||||
},
|
||||
success: {
|
||||
light: colors.successLight,
|
||||
200: colors.success200,
|
||||
main: colors.successMain,
|
||||
dark: colors.successDark
|
||||
},
|
||||
grey: {
|
||||
50: colors.grey50,
|
||||
100: colors.grey100,
|
||||
500: navType === 'dark' ? colors.darkTextSecondary : colors.grey500,
|
||||
600: navType === 'dark' ? colors.darkTextTitle : colors.grey900,
|
||||
700: navType === 'dark' ? colors.darkTextPrimary : colors.grey700,
|
||||
900: navType === 'dark' ? colors.darkTextPrimary : colors.grey900
|
||||
},
|
||||
dark: {
|
||||
light: colors.darkTextPrimary,
|
||||
main: colors.darkLevel1,
|
||||
dark: colors.darkLevel2,
|
||||
800: colors.darkBackground,
|
||||
900: colors.darkPaper
|
||||
},
|
||||
text: {
|
||||
primary: navType === 'dark' ? colors.darkTextPrimary : colors.grey700,
|
||||
secondary: navType === 'dark' ? colors.darkTextSecondary : colors.grey500,
|
||||
dark: navType === 'dark' ? colors.darkTextPrimary : colors.grey900,
|
||||
hint: colors.grey100
|
||||
},
|
||||
divider: navType === 'dark' ? colors.darkTextPrimary : colors.grey200,
|
||||
background: {
|
||||
paper: navType === 'dark' ? colors.darkLevel2 : colors.paper,
|
||||
default: navType === 'dark' ? colors.darkPaper : colors.paper
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export default Palette;
|
@ -0,0 +1,24 @@
|
||||
import { alpha } from '@mui/material/styles';
|
||||
|
||||
const createCustomShadow = (theme, color) => {
|
||||
const transparent = alpha(color, 0.24);
|
||||
return {
|
||||
z1: `0 1px 2px 0 ${transparent}`,
|
||||
z8: `0 8px 16px 0 ${transparent}`,
|
||||
z12: `0 12px 24px 0 ${transparent} 0 10px 20px 0 ${transparent}`,
|
||||
z16: `0 0 3px 0 ${transparent} 0 14px 28px -5px ${transparent}`,
|
||||
z20: `0 0 3px 0 ${transparent} 0 18px 36px -5px ${transparent}`,
|
||||
z24: `0 0 6px 0 ${transparent} 0 21px 44px 0 ${transparent}`,
|
||||
|
||||
primary: `0px 12px 14px 0px ${alpha(theme.palette.primary.main, 0.3)}`,
|
||||
secondary: `0px 12px 14px 0px ${alpha(theme.palette.secondary.main, 0.3)}`,
|
||||
orange: `0px 12px 14px 0px ${alpha(theme.palette.orange.main, 0.3)}`,
|
||||
success: `0px 12px 14px 0px ${alpha(theme.palette.success.main, 0.3)}`,
|
||||
warning: `0px 12px 14px 0px ${alpha(theme.palette.warning.main, 0.3)}`,
|
||||
error: `0px 12px 14px 0px ${alpha(theme.palette.error.main, 0.3)}`
|
||||
};
|
||||
};
|
||||
|
||||
export default function customShadows(navType, theme) {
|
||||
return navType === 'dark' ? createCustomShadow(theme, theme.palette.dark.main) : createCustomShadow(theme, theme.palette.grey[600]);
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
const Typography = (theme, borderRadius, fontFamily) => ({
|
||||
fontFamily,
|
||||
h6: {
|
||||
fontWeight: 500,
|
||||
color: theme.palette.grey[600],
|
||||
fontSize: '0.75rem'
|
||||
},
|
||||
h5: {
|
||||
fontSize: '0.875rem',
|
||||
color: theme.palette.grey[600],
|
||||
fontWeight: 500
|
||||
},
|
||||
h4: {
|
||||
fontSize: '1rem',
|
||||
color: theme.palette.grey[600],
|
||||
fontWeight: 600
|
||||
},
|
||||
h3: {
|
||||
fontSize: '1.25rem',
|
||||
color: theme.palette.grey[600],
|
||||
fontWeight: 600
|
||||
},
|
||||
h2: {
|
||||
fontSize: '1.5rem',
|
||||
color: theme.palette.grey[600],
|
||||
fontWeight: 700
|
||||
},
|
||||
h1: {
|
||||
fontSize: '2.125rem',
|
||||
color: theme.palette.grey[600],
|
||||
fontWeight: 700
|
||||
},
|
||||
subtitle1: {
|
||||
fontSize: '0.875rem',
|
||||
fontWeight: 500,
|
||||
color: theme.palette.text.dark
|
||||
},
|
||||
subtitle2: {
|
||||
fontSize: '0.75rem',
|
||||
fontWeight: 400,
|
||||
color: theme.palette.text.secondary
|
||||
},
|
||||
caption: {
|
||||
fontSize: '0.75rem',
|
||||
color: theme.palette.text.secondary,
|
||||
fontWeight: 400
|
||||
},
|
||||
body1: {
|
||||
fontSize: '0.875rem',
|
||||
fontWeight: 400,
|
||||
lineHeight: '1.334em'
|
||||
},
|
||||
body2: {
|
||||
letterSpacing: '0em',
|
||||
fontWeight: 400,
|
||||
lineHeight: '1.5em',
|
||||
color: theme.palette.text.primary
|
||||
},
|
||||
button: {
|
||||
textTransform: 'capitalize'
|
||||
},
|
||||
customInput: {
|
||||
marginTop: 1,
|
||||
marginBottom: 1,
|
||||
'& > label': {
|
||||
top: 23,
|
||||
left: 0,
|
||||
color: theme.palette.grey[500],
|
||||
'&[data-shrink="false"]': {
|
||||
top: 5
|
||||
}
|
||||
},
|
||||
'& > div > input': {
|
||||
padding: '30.5px 14px 11.5px !important'
|
||||
},
|
||||
'& legend': {
|
||||
display: 'none'
|
||||
},
|
||||
'& fieldset': {
|
||||
top: 0
|
||||
}
|
||||
},
|
||||
mainContent: {
|
||||
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.dark[800] : theme.palette.primary.light,
|
||||
width: '100%',
|
||||
minHeight: 'calc(100vh - 88px)',
|
||||
flexGrow: 1,
|
||||
padding: '20px',
|
||||
marginTop: '88px',
|
||||
marginRight: '20px',
|
||||
borderRadius: `${borderRadius}px`
|
||||
},
|
||||
menuCaption: {
|
||||
fontSize: '0.875rem',
|
||||
fontWeight: 500,
|
||||
color: theme.palette.grey[600],
|
||||
padding: '6px',
|
||||
textTransform: 'capitalize',
|
||||
marginTop: '10px'
|
||||
},
|
||||
subMenuCaption: {
|
||||
fontSize: '0.6875rem',
|
||||
fontWeight: 500,
|
||||
color: theme.palette.text.secondary,
|
||||
textTransform: 'capitalize'
|
||||
},
|
||||
commonAvatar: {
|
||||
cursor: 'pointer',
|
||||
borderRadius: '8px'
|
||||
},
|
||||
smallAvatar: {
|
||||
width: '22px',
|
||||
height: '22px',
|
||||
fontSize: '1rem'
|
||||
},
|
||||
mediumAvatar: {
|
||||
width: '34px',
|
||||
height: '34px',
|
||||
fontSize: '1.2rem'
|
||||
},
|
||||
largeAvatar: {
|
||||
width: '44px',
|
||||
height: '44px',
|
||||
fontSize: '1.5rem'
|
||||
}
|
||||
});
|
||||
|
||||
export default Typography;
|
@ -0,0 +1,15 @@
|
||||
import { Suspense } from 'react';
|
||||
|
||||
// project imports
|
||||
import Loader from './Loader';
|
||||
|
||||
// ==============================|| LOADABLE - LAZY LOADING ||============================== //
|
||||
|
||||
const Loadable = (Component) => (props) =>
|
||||
(
|
||||
<Suspense fallback={<Loader />}>
|
||||
<Component {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
export default Loadable;
|
@ -0,0 +1,22 @@
|
||||
// material-ui
|
||||
import LinearProgress from '@mui/material/LinearProgress';
|
||||
import { styled } from '@mui/material/styles';
|
||||
|
||||
// styles
|
||||
const LoaderWrapper = styled('div')({
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 1301,
|
||||
width: '100%'
|
||||
});
|
||||
|
||||
// ==============================|| LOADER ||============================== //
|
||||
|
||||
const Loader = () => (
|
||||
<LoaderWrapper>
|
||||
<LinearProgress color="primary" />
|
||||
</LoaderWrapper>
|
||||
);
|
||||
|
||||
export default Loader;
|
@ -0,0 +1,49 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
// third-party
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
|
||||
// load locales files
|
||||
const loadLocaleData = (locale) => {
|
||||
switch (locale) {
|
||||
case 'fr':
|
||||
return import('utils/locales/fr.json');
|
||||
case 'ro':
|
||||
return import('utils/locales/ro.json');
|
||||
case 'zh':
|
||||
return import('utils/locales/zh.json');
|
||||
default:
|
||||
return import('utils/locales/en.json');
|
||||
}
|
||||
};
|
||||
|
||||
// ==============================|| LOCALIZATION ||============================== //
|
||||
|
||||
const Locales = ({ children }) => {
|
||||
const { locale } = useConfig();
|
||||
const [messages, setMessages] = useState();
|
||||
|
||||
useEffect(() => {
|
||||
loadLocaleData(locale).then((d) => {
|
||||
setMessages(d.default);
|
||||
});
|
||||
}, [locale]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{messages && (
|
||||
<IntlProvider locale={locale} defaultLocale="en" messages={messages}>
|
||||
{children}
|
||||
</IntlProvider>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Locales.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default Locales;
|
@ -0,0 +1,69 @@
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
/**
|
||||
* if you want to use image instead of <svg> uncomment following.
|
||||
*
|
||||
* import logoDark from 'assets/images/logo-dark.svg';
|
||||
* import logo from 'assets/images/logo.svg';
|
||||
*
|
||||
*/
|
||||
|
||||
// ==============================|| LOGO SVG ||============================== //
|
||||
|
||||
const Logo = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
/**
|
||||
* if you want to use image instead of svg uncomment following, and comment out <svg> element.
|
||||
*
|
||||
* <img src={theme.palette.mode === 'dark' ? logoDark : logo} alt="Berry" width="100" />
|
||||
*
|
||||
*/
|
||||
<svg width="92" height="32" viewBox="0 0 92 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M33.085 26.4841V12.3839H37.9541C39.6408 12.3839 40.9202 12.7131 41.7922 13.3717C42.6642 14.0237 43.1002 14.9825 43.1002 16.2478C43.1002 16.9387 42.9251 17.5488 42.5751 18.0782C42.225 18.6011 41.7381 18.9853 41.1143 19.2306C41.8272 19.4114 42.3873 19.7761 42.7947 20.3249C43.2084 20.8737 43.4152 21.5452 43.4152 22.3392C43.4152 23.695 42.9888 24.7215 42.1359 25.4188C41.283 26.1161 40.0673 26.4712 38.4888 26.4841H33.085ZM35.9492 20.3443V24.1502H38.4028C39.0775 24.1502 39.6026 23.9888 39.9781 23.666C40.36 23.3367 40.551 22.8848 40.551 22.3102C40.551 21.0189 39.8922 20.3637 38.5747 20.3443H35.9492ZM35.9492 18.2912H38.0687C39.5135 18.2654 40.236 17.6811 40.236 16.5384C40.236 15.8992 40.0514 15.4408 39.6822 15.1632C39.3194 14.8792 38.7434 14.7371 37.9541 14.7371H35.9492V18.2912ZM53.9365 20.3733H48.4371V24.1502H54.8913V26.4841H45.573V12.3839H54.8723V14.7371H48.4371V18.0976H53.9365V20.3733ZM61.7175 21.3224H59.436V26.4841H56.5717V12.3839H61.7365C63.379 12.3839 64.6455 12.7551 65.5365 13.4975C66.4276 14.24 66.8734 15.2891 66.8734 16.6449C66.8734 17.6069 66.6661 18.4107 66.2527 19.0563C65.8455 19.6954 65.2248 20.2055 64.3907 20.5864L67.3985 26.3485V26.4841H64.3242L61.7175 21.3224ZM59.436 18.9691H61.746C62.4656 18.9691 63.0226 18.7851 63.417 18.4172C63.8114 18.0427 64.0092 17.5294 64.0092 16.8773C64.0092 16.2124 63.8214 15.6894 63.4455 15.3085C63.0768 14.9276 62.5069 14.7371 61.7365 14.7371H59.436V18.9691ZM74.2058 21.3224H71.9237V26.4841H69.0594V12.3839H74.2248C75.8667 12.3839 77.1337 12.7551 78.0248 13.4975C78.9159 14.24 79.3611 15.2891 79.3611 16.6449C79.3611 17.6069 79.1544 18.4107 78.7404 19.0563C78.3332 19.6954 77.7125 20.2055 76.879 20.5864L79.8863 26.3485V26.4841H76.8119L74.2058 21.3224ZM71.9237 18.9691H74.2343C74.9533 18.9691 75.5103 18.7851 75.9052 18.4172C76.2997 18.0427 76.4969 17.5294 76.4969 16.8773C76.4969 16.2124 76.3092 15.6894 75.9337 15.3085C75.5645 14.9276 74.9946 14.7371 74.2248 14.7371H71.9237V18.9691ZM85.8823 18.7367L88.7751 12.3839H91.9064L87.3427 21.3708V26.4841H84.4309V21.3708L79.8673 12.3839H83.008L85.8823 18.7367Z"
|
||||
fill={theme.palette.mode === 'dark' ? theme.palette.common.white : theme.palette.grey[900]}
|
||||
/>
|
||||
<path
|
||||
d="M10.987 31.5841C4.92849 31.5841 0 26.626 0 20.5323C0 14.4385 4.92899 9.48041 10.987 9.48041C17.045 9.48041 21.974 14.4385 21.974 20.5323C21.974 26.626 17.0459 31.5841 10.987 31.5841ZM10.987 10.536C5.50765 10.536 1.04938 15.0196 1.04938 20.5318C1.04938 26.044 5.50765 30.5275 10.987 30.5275C16.4663 30.5275 20.9251 26.0429 20.9251 20.5308C20.9251 15.0186 16.4673 10.536 10.987 10.536Z"
|
||||
fill={theme.palette.primary.main}
|
||||
/>
|
||||
<path
|
||||
d="M18.96 21.0225C18.6182 19.7483 15.4851 19.6108 13.6203 20.0779C12.6437 20.3235 11.6456 20.6428 10.6162 20.8265C11.3697 21.4989 12.1788 22.135 13.34 22.2932C16.2211 22.6842 18.0112 21.775 18.96 21.0225Z"
|
||||
fill={theme.palette.primary.main}
|
||||
/>
|
||||
<path
|
||||
d="M13.34 22.2932C12.1764 22.135 11.3697 21.4989 10.6162 20.8265C9.45013 19.7857 8.41298 18.6579 6.37723 19.0823C3.14069 19.7572 2.71488 23.6081 5.21404 26.0828C6.28706 27.2131 7.66455 28.0041 9.17779 28.3586C10.691 28.7132 12.2742 28.616 13.7333 28.079C15.1924 27.5419 16.4641 26.5883 17.3925 25.3352C18.3209 24.0819 18.8656 22.5835 18.96 21.0235C18.0112 21.775 16.221 22.6842 13.34 22.2932Z"
|
||||
fill={theme.palette.secondary.main}
|
||||
/>
|
||||
<path
|
||||
d="M15.034 13.9586C14.6301 14.8295 18.2304 15.7957 18.6611 18.6879C18.8687 15.8409 15.5335 12.882 15.034 13.9586Z"
|
||||
fill={theme.palette.primary.main}
|
||||
/>
|
||||
<path
|
||||
d="M7.46619 17.5935C8.11524 17.3231 8.42345 16.5746 8.15463 15.9217C7.8858 15.2688 7.14167 14.9587 6.49262 15.2292C5.84357 15.4996 5.53536 16.2481 5.80418 16.9011C6.07306 17.5539 6.81714 17.8639 7.46619 17.5935Z"
|
||||
fill={theme.palette.secondary.main}
|
||||
/>
|
||||
<path
|
||||
d="M10.3549 14.08C10.6585 13.7746 10.6585 13.2795 10.3549 12.9741C10.0513 12.6687 9.55909 12.6687 9.25551 12.9741C8.95194 13.2795 8.95194 13.7746 9.25551 14.08C9.55909 14.3854 10.0513 14.3854 10.3549 14.08Z"
|
||||
fill={theme.palette.primary.main}
|
||||
/>
|
||||
<path
|
||||
d="M13.1014 9.05206C14.2245 5.7149 13.4696 3.04871 11.1614 1.78241C9.58359 2.10513 8.647 2.87335 8.12549 3.93383C11.2204 3.68185 13.1844 5.63041 13.1014 9.05206Z"
|
||||
fill={theme.palette.primary.main}
|
||||
/>
|
||||
<path
|
||||
d="M25.6983 6.13641C20.1389 4.1294 16.6304 4.81756 16.0786 9.39055C19.2648 12.6973 22.474 11.1146 25.6983 6.13641Z"
|
||||
fill={theme.palette.primary.main}
|
||||
/>
|
||||
<path
|
||||
d="M21.2765 4.32541C21.5343 3.21728 21.6681 1.90776 21.6881 0.41748C15.9226 1.70883 13.3224 4.17658 15.2839 8.33846C15.3816 8.36203 15.4754 8.38119 15.5696 8.40085C16.0281 5.14422 18.0463 3.93835 21.2765 4.32541Z"
|
||||
fill={theme.palette.primary.main}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default Logo;
|
@ -0,0 +1,34 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { CacheProvider } from '@emotion/react';
|
||||
import createCache from '@emotion/cache';
|
||||
|
||||
// third-party
|
||||
import rtlPlugin from 'stylis-plugin-rtl';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
|
||||
// ==============================|| RTL LAYOUT ||============================== //
|
||||
|
||||
const RTLLayout = ({ children }) => {
|
||||
const { rtlLayout } = useConfig();
|
||||
|
||||
useEffect(() => {
|
||||
document.dir = rtlLayout ? 'rtl' : 'ltr';
|
||||
}, [rtlLayout]);
|
||||
|
||||
const cacheRtl = createCache({
|
||||
key: rtlLayout ? 'rtl' : 'css',
|
||||
prepend: true,
|
||||
stylisPlugins: rtlLayout ? [rtlPlugin] : []
|
||||
});
|
||||
|
||||
return <CacheProvider value={cacheRtl}>{children}</CacheProvider>;
|
||||
};
|
||||
|
||||
RTLLayout.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default RTLLayout;
|
@ -0,0 +1,127 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useState } from 'react';
|
||||
|
||||
// material-ui
|
||||
import { Box, Button, Grid, Menu, MenuItem, Typography } from '@mui/material';
|
||||
|
||||
// third party
|
||||
import Chart from 'react-apexcharts';
|
||||
|
||||
// project imports
|
||||
import MainCard from './MainCard';
|
||||
|
||||
// assets
|
||||
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
|
||||
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
|
||||
|
||||
// ==========================|| ANALYTICS CHART CARD ||========================== //
|
||||
|
||||
const AnalyticsChartCard = ({ title, chartData, dropData, listData }) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
let dropHtml;
|
||||
if (dropData) {
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event?.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
dropHtml = (
|
||||
<>
|
||||
<Button variant="text" disableElevation size="small" aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
|
||||
{dropData.title}
|
||||
</Button>
|
||||
<Menu
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'right'
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'right'
|
||||
}}
|
||||
id="simple-menu"
|
||||
anchorEl={anchorEl}
|
||||
keepMounted
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={handleClose}
|
||||
>
|
||||
{dropData?.options.map((option, index) => (
|
||||
<MenuItem key={index} onClick={handleClose}>
|
||||
{option.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
let listItem;
|
||||
if (listData) {
|
||||
listItem = listData.map((item, index) => (
|
||||
<Grid item key={index} sm={12}>
|
||||
<Box
|
||||
sx={{
|
||||
color: item.color
|
||||
}}
|
||||
>
|
||||
<Grid container spacing={2} justifyContent="center">
|
||||
<Grid item>{item.icon}</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle1">{item.value}%</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
{item.state === 1 && <ArrowUpwardIcon fontSize="inherit" color="inherit" />}
|
||||
{item.state === 0 && <ArrowDownwardIcon fontSize="inherit" color="inherit" />}
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle1" color="inherit">
|
||||
{item.percentage}%
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Grid>
|
||||
));
|
||||
}
|
||||
|
||||
return (
|
||||
<MainCard>
|
||||
<Grid container justifyContent="space-between" alignItems="center">
|
||||
{title && (
|
||||
<Grid item>
|
||||
<Typography variant="subtitle1">{title}</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item>{dropHtml}</Grid>
|
||||
</Grid>
|
||||
<Grid container justifyContent="center" alignItems="center">
|
||||
<Grid item container direction="column" spacing={1} xs={12} sm={6}>
|
||||
<Box
|
||||
sx={{
|
||||
mt: 3,
|
||||
display: 'block'
|
||||
}}
|
||||
>
|
||||
{listItem}
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Chart {...chartData} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</MainCard>
|
||||
);
|
||||
};
|
||||
|
||||
AnalyticsChartCard.propTypes = {
|
||||
title: PropTypes.string,
|
||||
chartData: PropTypes.object,
|
||||
dropData: PropTypes.object,
|
||||
listData: PropTypes.array
|
||||
};
|
||||
|
||||
export default AnalyticsChartCard;
|
@ -0,0 +1,43 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Card, CardContent, CardMedia, Grid, Typography } from '@mui/material';
|
||||
import { gridSpacing } from 'store/constant';
|
||||
|
||||
// assets
|
||||
import DownloadForOfflineTwoToneIcon from '@mui/icons-material/DownloadForOfflineTwoTone';
|
||||
|
||||
const backImage = require.context('assets/images/profile', true);
|
||||
|
||||
// ==============================|| ATTACHMENT CARD ||============================== //
|
||||
|
||||
const AttachmentCard = ({ title, image }) => {
|
||||
const theme = useTheme();
|
||||
const backProfile = image && backImage(`./${image}`).default;
|
||||
|
||||
return (
|
||||
<Card sx={{ bgcolor: theme.palette.mode === 'dark' ? 'dark.dark' : 'grey.100' }}>
|
||||
<CardMedia component="img" image={backProfile} title="Slider5 image" />
|
||||
<CardContent sx={{ p: 2, pb: '16px !important' }}>
|
||||
<Grid container spacing={gridSpacing}>
|
||||
<Grid item xs zeroMinWidth>
|
||||
<Typography variant="h5" component="div" sx={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
||||
{title}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<DownloadForOfflineTwoToneIcon sx={{ cursor: 'pointer' }} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
AttachmentCard.propTypes = {
|
||||
image: PropTypes.string,
|
||||
title: PropTypes.oneOfType([PropTypes.node, PropTypes.string, PropTypes.object])
|
||||
};
|
||||
|
||||
export default AttachmentCard;
|
@ -0,0 +1,17 @@
|
||||
// material-ui
|
||||
import { Link, Typography, Stack } from '@mui/material';
|
||||
|
||||
// ==============================|| FOOTER - AUTHENTICATION 2 & 3 ||============================== //
|
||||
|
||||
const AuthFooter = () => (
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="subtitle2" component={Link} href="https://berrydashboard.io" target="_blank" underline="hover">
|
||||
berrydashboard.io
|
||||
</Typography>
|
||||
<Typography variant="subtitle2" component={Link} href="https://codedthemes.com" target="_blank" underline="hover">
|
||||
© codedthemes.com
|
||||
</Typography>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
export default AuthFooter;
|
@ -0,0 +1,40 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { Grid, Typography } from '@mui/material';
|
||||
|
||||
// third-party
|
||||
import Slider from 'react-slick';
|
||||
|
||||
const AuthSlider = ({ items }) => {
|
||||
const settings = {
|
||||
autoplay: true,
|
||||
arrows: false,
|
||||
dots: true,
|
||||
infinite: true,
|
||||
speed: 500,
|
||||
slidesToShow: 1,
|
||||
slidesToScroll: 1
|
||||
};
|
||||
|
||||
return (
|
||||
<Slider {...settings}>
|
||||
{items.map((item, i) => (
|
||||
<Grid key={i} container direction="column" alignItems="center" spacing={3} textAlign="center">
|
||||
<Grid item>
|
||||
<Typography variant="h1">{item.title}</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">{item.description}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
))}
|
||||
</Slider>
|
||||
);
|
||||
};
|
||||
|
||||
AuthSlider.propTypes = {
|
||||
items: PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
export default AuthSlider;
|
@ -0,0 +1,43 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Box } from '@mui/material';
|
||||
|
||||
// assets
|
||||
import AuthPattern from 'assets/images/auth/auth-pattern.svg';
|
||||
import AuthPatternDark from 'assets/images/auth/auth-pattern-dark.svg';
|
||||
|
||||
// ===========================|| BACKGROUND GRID PATTERN 1 ||=========================== //
|
||||
|
||||
const BackgroundPattern1 = ({ children }) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
display: 'flex',
|
||||
minHeight: '100vh',
|
||||
bgcolor: theme.palette.mode === 'dark' ? theme.palette.dark.dark : '#fff',
|
||||
backgroundImage: theme.palette.mode === 'dark' ? `url(${AuthPatternDark})` : `url(${AuthPattern})`,
|
||||
position: 'absolute',
|
||||
backgroundPosition: '0 0',
|
||||
overflow: 'hidden',
|
||||
m: '0 0 0 auto',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
opacity: theme.palette.mode === 'dark' ? 0.85 : 0.9
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
BackgroundPattern1.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default BackgroundPattern1;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue