update,
This commit is contained in:
5
tsc1877/task1/aws/workspace/.env.example
Normal file
5
tsc1877/task1/aws/workspace/.env.example
Normal file
@@ -0,0 +1,5 @@
|
||||
DB_HOST=localhost
|
||||
DB_PORT=6033
|
||||
DB_NAME=app_db
|
||||
DB_USER=db_user
|
||||
DB_PASSWORD=db_user_pass
|
12
tsc1877/task1/aws/workspace/README.md
Normal file
12
tsc1877/task1/aws/workspace/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
```batch
|
||||
|
||||
> .\dc_up.bat
|
||||
|
||||
```
|
||||
|
||||
*nix
|
||||
```batch
|
||||
|
||||
> .\dc_up.sh
|
||||
|
||||
```
|
@@ -0,0 +1,51 @@
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box';
|
||||
import Card from '@mui/material/Card';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
|
||||
// ** Icons Imports
|
||||
import DotsVertical from 'mdi-material-ui/DotsVertical';
|
||||
|
||||
const CardStatsVertical = props => {
|
||||
// ** Props
|
||||
const { title, subtitle, color, icon, stats, trend, trendNumber } = props;
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Box sx={{ display: 'flex', marginBottom: 5.5, alignItems: 'flex-start', justifyContent: 'space-between' }}>
|
||||
<Avatar sx={{ boxShadow: 3, marginRight: 4, color: 'common.white', backgroundColor: `${color}.main` }}>
|
||||
{icon}
|
||||
</Avatar>
|
||||
<IconButton size="small" aria-label="settings" className="card-more-options" sx={{ color: 'text.secondary' }}>
|
||||
<DotsVertical />
|
||||
</IconButton>
|
||||
</Box>
|
||||
<Typography sx={{ fontWeight: 600, fontSize: '0.875rem' }}>{title}</Typography>
|
||||
<Box sx={{ marginTop: 1.5, display: 'flex', flexWrap: 'wrap', marginBottom: 1.5, alignItems: 'flex-start' }}>
|
||||
<Typography variant="h6" sx={{ mr: 2 }}>
|
||||
{stats}
|
||||
</Typography>
|
||||
<Typography
|
||||
component="sup"
|
||||
variant="caption"
|
||||
sx={{ color: trend === 'positive' ? 'success.main' : 'error.main' }}
|
||||
>
|
||||
{trendNumber}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography variant="caption">{subtitle}</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardStatsVertical;
|
||||
|
||||
CardStatsVertical.defaultProps = {
|
||||
color: 'primary',
|
||||
trend: 'positive',
|
||||
};
|
7
tsc1877/task1/aws/workspace/admin/src/@core/components/react-apexcharts/index.js
vendored
Normal file
7
tsc1877/task1/aws/workspace/admin/src/@core/components/react-apexcharts/index.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// ** Next Import
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
// ! To avoid 'Window is not defined' error
|
||||
const ReactApexcharts = dynamic(() => import('react-apexcharts'), { ssr: false });
|
||||
|
||||
export default ReactApexcharts;
|
@@ -0,0 +1,39 @@
|
||||
// ** MUI Imports
|
||||
import Zoom from '@mui/material/Zoom';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import useScrollTrigger from '@mui/material/useScrollTrigger';
|
||||
|
||||
const ScrollToTopStyled = styled('div')(({ theme }) => ({
|
||||
zIndex: 11,
|
||||
position: 'fixed',
|
||||
right: theme.spacing(6),
|
||||
bottom: theme.spacing(10),
|
||||
}));
|
||||
|
||||
const ScrollToTop = props => {
|
||||
// ** Props
|
||||
const { children, className } = props;
|
||||
|
||||
// ** init trigger
|
||||
const trigger = useScrollTrigger({
|
||||
threshold: 400,
|
||||
disableHysteresis: true,
|
||||
});
|
||||
|
||||
const handleClick = () => {
|
||||
const anchor = document.querySelector('body');
|
||||
if (anchor) {
|
||||
anchor.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Zoom in={trigger}>
|
||||
<ScrollToTopStyled className={className} onClick={handleClick} role="presentation">
|
||||
{children}
|
||||
</ScrollToTopStyled>
|
||||
</Zoom>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScrollToTop;
|
@@ -0,0 +1,30 @@
|
||||
// ** React Imports
|
||||
import { createContext, useState } from 'react';
|
||||
|
||||
// ** ThemeConfig Import
|
||||
import themeConfig from 'src/configs/themeConfig';
|
||||
|
||||
const initialSettings = {
|
||||
themeColor: 'primary',
|
||||
mode: themeConfig.mode,
|
||||
contentWidth: themeConfig.contentWidth,
|
||||
};
|
||||
|
||||
// ** Create Context
|
||||
export const SettingsContext = createContext({
|
||||
saveSettings: () => null,
|
||||
settings: initialSettings,
|
||||
});
|
||||
|
||||
export const SettingsProvider = ({ children }) => {
|
||||
// ** State
|
||||
const [settings, setSettings] = useState({ ...initialSettings });
|
||||
|
||||
const saveSettings = updatedSettings => {
|
||||
setSettings(updatedSettings);
|
||||
};
|
||||
|
||||
return <SettingsContext.Provider value={{ settings, saveSettings }}>{children}</SettingsContext.Provider>;
|
||||
};
|
||||
|
||||
export const SettingsConsumer = SettingsContext.Consumer;
|
@@ -0,0 +1,4 @@
|
||||
import { useContext } from 'react';
|
||||
import { SettingsContext } from 'src/@core/context/settingsContext';
|
||||
|
||||
export const useSettings = () => useContext(SettingsContext);
|
@@ -0,0 +1,37 @@
|
||||
// ** MUI Imports
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
// Styled component for Blank Layout component
|
||||
const BlankLayoutWrapper = styled(Box)(({ theme }) => ({
|
||||
height: '100vh',
|
||||
|
||||
// For V1 Blank layout pages
|
||||
'& .content-center': {
|
||||
display: 'flex',
|
||||
minHeight: '100vh',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: theme.spacing(5),
|
||||
},
|
||||
|
||||
// For V2 Blank layout pages
|
||||
'& .content-right': {
|
||||
display: 'flex',
|
||||
minHeight: '100vh',
|
||||
overflowX: 'hidden',
|
||||
position: 'relative',
|
||||
},
|
||||
}));
|
||||
|
||||
const BlankLayout = ({ children }) => {
|
||||
return (
|
||||
<BlankLayoutWrapper className="layout-wrapper">
|
||||
<Box className="app-content" sx={{ minHeight: '100vh', overflowX: 'hidden', position: 'relative' }}>
|
||||
{children}
|
||||
</Box>
|
||||
</BlankLayoutWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlankLayout;
|
@@ -0,0 +1,104 @@
|
||||
// ** MUI Imports
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Box from '@mui/material/Box';
|
||||
import { Badge, Button, IconButton, Stack, Typography } from '@mui/material';
|
||||
import { useRouter } from 'next/router';
|
||||
import HomeIcon from '@mui/icons-material/Home';
|
||||
import { CartConsumer, CartContext, CartProvider } from 'src/contexts/cart';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import CartIcon from './components/CartIcon';
|
||||
import AccountBoxIcon from '@mui/icons-material/AccountBox';
|
||||
import CheckSession from 'src/api/checkSession';
|
||||
import { AuthContext, AuthProvider } from 'src/contexts/auth';
|
||||
|
||||
// Styled component for Blank Layout component
|
||||
const ShopfrontLayoutWrapper = styled(Box)(({ theme }) => ({
|
||||
height: '100vh',
|
||||
|
||||
// For V1 Blank layout pages
|
||||
'& .content-center': {
|
||||
display: 'flex',
|
||||
minHeight: '100vh',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: theme.spacing(5),
|
||||
},
|
||||
|
||||
// For V2 Blank layout pages
|
||||
'& .content-right': {
|
||||
display: 'flex',
|
||||
minHeight: '100vh',
|
||||
overflowX: 'hidden',
|
||||
position: 'relative',
|
||||
},
|
||||
}));
|
||||
|
||||
const ShopfrontLayout = ({ children }) => {
|
||||
const router = useRouter();
|
||||
const [data, setData] = useState({});
|
||||
const { username, setUsername } = useContext(AuthContext);
|
||||
|
||||
useEffect(() => {
|
||||
const check = async () => {
|
||||
try {
|
||||
let { session } = JSON.parse(localStorage.getItem('session')) || '';
|
||||
|
||||
let data = await CheckSession({ session });
|
||||
if (data['status'] != 'OK') {
|
||||
return route.replace('/shopfront/login');
|
||||
} else {
|
||||
setData(data);
|
||||
setUsername(data['username']);
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
return check();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<CartProvider>
|
||||
<ShopfrontLayoutWrapper className="layout-wrapper">
|
||||
<Box className="app-content" sx={{ minHeight: '100vh', overflowX: 'hidden', position: 'relative' }}>
|
||||
<Stack direction="column" alignItems={'center'} justifyContent={'center'}>
|
||||
<Box sx={{ width: '80vw' }}>
|
||||
<Stack direction="column">
|
||||
<Stack direction="row" justifyContent={'space-between'} alignItems={'center'} minHeight={'10vh'}>
|
||||
<Box style={{ width: 'calc ( 80vw / 3 )' }}>
|
||||
<Typography variant="h5">Hi, {username || 'Guest'}</Typography>
|
||||
</Box>
|
||||
<Box style={{ width: 'calc ( 80vw / 3 )' }}>
|
||||
<Typography variant="h5">VTKH Mall</Typography>
|
||||
</Box>
|
||||
|
||||
<Box style={{ width: 'calc ( 80vw / 3 )' }}>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
router.push('/shopfront/customer/profile');
|
||||
}}
|
||||
>
|
||||
<AccountBoxIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
router.push('/shopfront');
|
||||
}}
|
||||
>
|
||||
<HomeIcon />
|
||||
</IconButton>
|
||||
|
||||
<CartIcon />
|
||||
</Box>
|
||||
</Stack>
|
||||
{children}
|
||||
<Box height={'5rem'}></Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
</ShopfrontLayoutWrapper>
|
||||
</CartProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default ShopfrontLayout;
|
@@ -0,0 +1,109 @@
|
||||
// ** React Imports
|
||||
import { useState } from 'react';
|
||||
|
||||
// ** MUI Imports
|
||||
import Fab from '@mui/material/Fab';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
// ** Icons Imports
|
||||
import ArrowUp from 'mdi-material-ui/ArrowUp';
|
||||
|
||||
// ** Theme Config Import
|
||||
import themeConfig from 'src/configs/themeConfig';
|
||||
|
||||
// ** Components
|
||||
import AppBar from './components/vertical/appBar';
|
||||
import Navigation from './components/vertical/navigation';
|
||||
import Footer from './components/shared-components/footer';
|
||||
import ScrollToTop from 'src/@core/components/scroll-to-top';
|
||||
|
||||
// ** Styled Component
|
||||
import DatePickerWrapper from 'src/@core/styles/libs/react-datepicker';
|
||||
|
||||
const VerticalLayoutWrapper = styled('div')({
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
});
|
||||
|
||||
const MainContentWrapper = styled(Box)({
|
||||
flexGrow: 1,
|
||||
minWidth: 0,
|
||||
display: 'flex',
|
||||
minHeight: '100vh',
|
||||
flexDirection: 'column',
|
||||
});
|
||||
|
||||
const ContentWrapper = styled('main')(({ theme }) => ({
|
||||
flexGrow: 1,
|
||||
width: '100%',
|
||||
padding: theme.spacing(6),
|
||||
transition: 'padding .25s ease-in-out',
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
paddingLeft: theme.spacing(4),
|
||||
paddingRight: theme.spacing(4),
|
||||
},
|
||||
}));
|
||||
|
||||
const VerticalLayout = props => {
|
||||
// ** Props
|
||||
const { settings, children, scrollToTop } = props;
|
||||
|
||||
// ** Vars
|
||||
const { contentWidth } = settings;
|
||||
const navWidth = themeConfig.navigationSize;
|
||||
|
||||
// ** States
|
||||
const [navVisible, setNavVisible] = useState(false);
|
||||
|
||||
// ** Toggle Functions
|
||||
const toggleNavVisibility = () => setNavVisible(!navVisible);
|
||||
|
||||
return (
|
||||
<>
|
||||
<VerticalLayoutWrapper className="layout-wrapper">
|
||||
<Navigation
|
||||
navWidth={navWidth}
|
||||
navVisible={navVisible}
|
||||
setNavVisible={setNavVisible}
|
||||
toggleNavVisibility={toggleNavVisibility}
|
||||
{...props}
|
||||
/>
|
||||
<MainContentWrapper className="layout-content-wrapper">
|
||||
<AppBar toggleNavVisibility={toggleNavVisibility} {...props} />
|
||||
|
||||
<ContentWrapper
|
||||
className="layout-page-content"
|
||||
sx={{
|
||||
...(contentWidth === 'boxed' && {
|
||||
mx: 'auto',
|
||||
'@media (min-width:1440px)': { maxWidth: 1440 },
|
||||
'@media (min-width:1200px)': { maxWidth: '100%' },
|
||||
}),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ContentWrapper>
|
||||
|
||||
<Footer {...props} />
|
||||
|
||||
<DatePickerWrapper sx={{ zIndex: 11 }}>
|
||||
<Box id="react-datepicker-portal"></Box>
|
||||
</DatePickerWrapper>
|
||||
</MainContentWrapper>
|
||||
</VerticalLayoutWrapper>
|
||||
|
||||
{scrollToTop ? (
|
||||
scrollToTop(props)
|
||||
) : (
|
||||
<ScrollToTop className="mui-fixed">
|
||||
<Fab color="primary" size="small" aria-label="scroll back to top">
|
||||
<ArrowUp />
|
||||
</Fab>
|
||||
</ScrollToTop>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default VerticalLayout;
|
@@ -0,0 +1,29 @@
|
||||
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
|
||||
|
||||
import { Badge, IconButton } from '@mui/material';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useContext } from 'react';
|
||||
import { CartContext } from 'src/contexts/cart';
|
||||
|
||||
function CartIcon() {
|
||||
let router = useRouter();
|
||||
let { cart } = useContext(CartContext);
|
||||
|
||||
if (!cart) return <></>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
router.push('/shopfront/cart');
|
||||
}}
|
||||
>
|
||||
<Badge badgeContent={cart?.length} color="primary">
|
||||
<ShoppingCartIcon />
|
||||
</Badge>
|
||||
</IconButton>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CartIcon;
|
@@ -0,0 +1,30 @@
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
|
||||
// ** Icons Imports
|
||||
import WeatherNight from 'mdi-material-ui/WeatherNight';
|
||||
import WeatherSunny from 'mdi-material-ui/WeatherSunny';
|
||||
|
||||
const ModeToggler = props => {
|
||||
// ** Props
|
||||
const { settings, saveSettings } = props;
|
||||
|
||||
const handleModeChange = mode => {
|
||||
saveSettings({ ...settings, mode });
|
||||
};
|
||||
|
||||
const handleModeToggle = () => {
|
||||
if (settings.mode === 'light') {
|
||||
handleModeChange('dark');
|
||||
} else {
|
||||
handleModeChange('light');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<IconButton color="inherit" aria-haspopup="true" onClick={handleModeToggle}>
|
||||
{settings.mode === 'dark' ? <WeatherSunny /> : <WeatherNight />}
|
||||
</IconButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModeToggler;
|
@@ -0,0 +1,217 @@
|
||||
// ** React Imports
|
||||
import { useState, Fragment } from 'react';
|
||||
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import Button from '@mui/material/Button';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
import MuiMenu from '@mui/material/Menu';
|
||||
import MuiAvatar from '@mui/material/Avatar';
|
||||
import MuiMenuItem from '@mui/material/MenuItem';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
// ** Icons Imports
|
||||
import BellOutline from 'mdi-material-ui/BellOutline';
|
||||
|
||||
// ** Third Party Components
|
||||
import PerfectScrollbarComponent from 'react-perfect-scrollbar';
|
||||
|
||||
// ** Styled Menu component
|
||||
const Menu = styled(MuiMenu)(({ theme }) => ({
|
||||
'& .MuiMenu-paper': {
|
||||
width: 380,
|
||||
overflow: 'hidden',
|
||||
marginTop: theme.spacing(4),
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
'& .MuiMenu-list': {
|
||||
padding: 0,
|
||||
},
|
||||
}));
|
||||
|
||||
// ** Styled MenuItem component
|
||||
const MenuItem = styled(MuiMenuItem)(({ theme }) => ({
|
||||
paddingTop: theme.spacing(3),
|
||||
paddingBottom: theme.spacing(3),
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
}));
|
||||
|
||||
const styles = {
|
||||
maxHeight: 349,
|
||||
'& .MuiMenuItem-root:last-of-type': {
|
||||
border: 0,
|
||||
},
|
||||
};
|
||||
|
||||
// ** Styled PerfectScrollbar component
|
||||
const PerfectScrollbar = styled(PerfectScrollbarComponent)({
|
||||
...styles,
|
||||
});
|
||||
|
||||
// ** Styled Avatar component
|
||||
const Avatar = styled(MuiAvatar)({
|
||||
width: '2.375rem',
|
||||
height: '2.375rem',
|
||||
fontSize: '1.125rem',
|
||||
});
|
||||
|
||||
// ** Styled component for the title in MenuItems
|
||||
const MenuItemTitle = styled(Typography)(({ theme }) => ({
|
||||
fontWeight: 600,
|
||||
flex: '1 1 100%',
|
||||
overflow: 'hidden',
|
||||
fontSize: '0.875rem',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
marginBottom: theme.spacing(0.75),
|
||||
}));
|
||||
|
||||
// ** Styled component for the subtitle in MenuItems
|
||||
const MenuItemSubtitle = styled(Typography)({
|
||||
flex: '1 1 100%',
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
});
|
||||
|
||||
const NotificationDropdown = () => {
|
||||
// ** States
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
// ** Hook
|
||||
const hidden = useMediaQuery(theme => theme.breakpoints.down('lg'));
|
||||
|
||||
const handleDropdownOpen = event => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleDropdownClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const ScrollWrapper = ({ children }) => {
|
||||
if (hidden) {
|
||||
return <Box sx={{ ...styles, overflowY: 'auto', overflowX: 'hidden' }}>{children}</Box>;
|
||||
} else {
|
||||
return (
|
||||
<PerfectScrollbar options={{ wheelPropagation: false, suppressScrollX: true }}>{children}</PerfectScrollbar>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<IconButton color="inherit" aria-haspopup="true" onClick={handleDropdownOpen} aria-controls="customized-menu">
|
||||
<BellOutline />
|
||||
</IconButton>
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={handleDropdownClose}
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
||||
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
|
||||
>
|
||||
<MenuItem disableRipple>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%' }}>
|
||||
<Typography sx={{ fontWeight: 600 }}>Notifications</Typography>
|
||||
<Chip
|
||||
size="small"
|
||||
label="8 New"
|
||||
color="primary"
|
||||
sx={{ height: 20, fontSize: '0.75rem', fontWeight: 500, borderRadius: '10px' }}
|
||||
/>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<ScrollWrapper>
|
||||
<MenuItem onClick={handleDropdownClose}>
|
||||
<Box sx={{ width: '100%', display: 'flex', alignItems: 'center' }}>
|
||||
<Avatar alt="Flora" src="/images/avatars/4.png" />
|
||||
<Box sx={{ mx: 4, flex: '1 1', display: 'flex', overflow: 'hidden', flexDirection: 'column' }}>
|
||||
<MenuItemTitle>Congratulation Flora! 🎉</MenuItemTitle>
|
||||
<MenuItemSubtitle variant="body2">Won the monthly best seller badge</MenuItemSubtitle>
|
||||
</Box>
|
||||
<Typography variant="caption" sx={{ color: 'text.disabled' }}>
|
||||
Today
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleDropdownClose}>
|
||||
<Box sx={{ width: '100%', display: 'flex', alignItems: 'center' }}>
|
||||
<Avatar sx={{ color: 'common.white', backgroundColor: 'primary.main' }}>VU</Avatar>
|
||||
<Box sx={{ mx: 4, flex: '1 1', display: 'flex', overflow: 'hidden', flexDirection: 'column' }}>
|
||||
<MenuItemTitle>New user registered.</MenuItemTitle>
|
||||
<MenuItemSubtitle variant="body2">5 hours ago</MenuItemSubtitle>
|
||||
</Box>
|
||||
<Typography variant="caption" sx={{ color: 'text.disabled' }}>
|
||||
Yesterday
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleDropdownClose}>
|
||||
<Box sx={{ width: '100%', display: 'flex', alignItems: 'center' }}>
|
||||
<Avatar alt="message" src="/images/avatars/5.png" />
|
||||
<Box sx={{ mx: 4, flex: '1 1', display: 'flex', overflow: 'hidden', flexDirection: 'column' }}>
|
||||
<MenuItemTitle>New message received 👋🏻</MenuItemTitle>
|
||||
<MenuItemSubtitle variant="body2">You have 10 unread messages</MenuItemSubtitle>
|
||||
</Box>
|
||||
<Typography variant="caption" sx={{ color: 'text.disabled' }}>
|
||||
11 Aug
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleDropdownClose}>
|
||||
<Box sx={{ width: '100%', display: 'flex', alignItems: 'center' }}>
|
||||
<img width={38} height={38} alt="paypal" src="/images/misc/paypal.png" />
|
||||
<Box sx={{ mx: 4, flex: '1 1', display: 'flex', overflow: 'hidden', flexDirection: 'column' }}>
|
||||
<MenuItemTitle>Paypal</MenuItemTitle>
|
||||
<MenuItemSubtitle variant="body2">Received Payment</MenuItemSubtitle>
|
||||
</Box>
|
||||
<Typography variant="caption" sx={{ color: 'text.disabled' }}>
|
||||
25 May
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleDropdownClose}>
|
||||
<Box sx={{ width: '100%', display: 'flex', alignItems: 'center' }}>
|
||||
<Avatar alt="order" src="/images/avatars/3.png" />
|
||||
<Box sx={{ mx: 4, flex: '1 1', display: 'flex', overflow: 'hidden', flexDirection: 'column' }}>
|
||||
<MenuItemTitle>Revised Order 📦</MenuItemTitle>
|
||||
<MenuItemSubtitle variant="body2">New order revised from john</MenuItemSubtitle>
|
||||
</Box>
|
||||
<Typography variant="caption" sx={{ color: 'text.disabled' }}>
|
||||
19 Mar
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleDropdownClose}>
|
||||
<Box sx={{ width: '100%', display: 'flex', alignItems: 'center' }}>
|
||||
<img width={38} height={38} alt="chart" src="/images/misc/chart.png" />
|
||||
<Box sx={{ mx: 4, flex: '1 1', display: 'flex', overflow: 'hidden', flexDirection: 'column' }}>
|
||||
<MenuItemTitle>Finance report has been generated</MenuItemTitle>
|
||||
<MenuItemSubtitle variant="body2">25 hrs ago</MenuItemSubtitle>
|
||||
</Box>
|
||||
<Typography variant="caption" sx={{ color: 'text.disabled' }}>
|
||||
27 Dec
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
</ScrollWrapper>
|
||||
<MenuItem
|
||||
disableRipple
|
||||
sx={{ py: 3.5, borderBottom: 0, borderTop: theme => `1px solid ${theme.palette.divider}` }}
|
||||
>
|
||||
<Button fullWidth variant="contained" onClick={handleDropdownClose}>
|
||||
Read All Notifications
|
||||
</Button>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotificationDropdown;
|
@@ -0,0 +1,143 @@
|
||||
// ** React Imports
|
||||
import { useState, Fragment } from 'react';
|
||||
|
||||
// ** Next Import
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import Badge from '@mui/material/Badge';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
// ** Icons Imports
|
||||
import CogOutline from 'mdi-material-ui/CogOutline';
|
||||
import CurrencyUsd from 'mdi-material-ui/CurrencyUsd';
|
||||
import EmailOutline from 'mdi-material-ui/EmailOutline';
|
||||
import LogoutVariant from 'mdi-material-ui/LogoutVariant';
|
||||
import AccountOutline from 'mdi-material-ui/AccountOutline';
|
||||
import MessageOutline from 'mdi-material-ui/MessageOutline';
|
||||
import HelpCircleOutline from 'mdi-material-ui/HelpCircleOutline';
|
||||
|
||||
// ** Styled Components
|
||||
const BadgeContentSpan = styled('span')(({ theme }) => ({
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: theme.palette.success.main,
|
||||
boxShadow: `0 0 0 2px ${theme.palette.background.paper}`,
|
||||
}));
|
||||
|
||||
const UserDropdown = () => {
|
||||
// ** States
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
// ** Hooks
|
||||
const router = useRouter();
|
||||
|
||||
const handleDropdownOpen = event => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleDropdownClose = url => {
|
||||
if (url) {
|
||||
router.push(url);
|
||||
}
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const styles = {
|
||||
py: 2,
|
||||
px: 4,
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
color: 'text.primary',
|
||||
textDecoration: 'none',
|
||||
'& svg': {
|
||||
fontSize: '1.375rem',
|
||||
color: 'text.secondary',
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Badge>Hello user,</Badge>
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={() => handleDropdownClose()}
|
||||
sx={{ '& .MuiMenu-paper': { width: 230, marginTop: 4 } }}
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
||||
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
|
||||
>
|
||||
<Box sx={{ pt: 2, pb: 3, px: 4 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Badge
|
||||
overlap="circular"
|
||||
badgeContent={<BadgeContentSpan />}
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
||||
>
|
||||
<Avatar alt="John Doe" src="/images/avatars/1.png" sx={{ width: '2.5rem', height: '2.5rem' }} />
|
||||
</Badge>
|
||||
<Box sx={{ display: 'flex', marginLeft: 3, alignItems: 'flex-start', flexDirection: 'column' }}>
|
||||
<Typography sx={{ fontWeight: 600 }}>John Doe</Typography>
|
||||
<Typography variant="body2" sx={{ fontSize: '0.8rem', color: 'text.disabled' }}>
|
||||
Admin
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
<Divider sx={{ mt: 0, mb: 1 }} />
|
||||
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
|
||||
<Box sx={styles}>
|
||||
<AccountOutline sx={{ marginRight: 2 }} />
|
||||
Profile
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
|
||||
<Box sx={styles}>
|
||||
<EmailOutline sx={{ marginRight: 2 }} />
|
||||
Inbox
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
|
||||
<Box sx={styles}>
|
||||
<MessageOutline sx={{ marginRight: 2 }} />
|
||||
Chat
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<Divider />
|
||||
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
|
||||
<Box sx={styles}>
|
||||
<CogOutline sx={{ marginRight: 2 }} />
|
||||
Settings
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
|
||||
<Box sx={styles}>
|
||||
<CurrencyUsd sx={{ marginRight: 2 }} />
|
||||
Pricing
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
|
||||
<Box sx={styles}>
|
||||
<HelpCircleOutline sx={{ marginRight: 2 }} />
|
||||
FAQ
|
||||
</Box>
|
||||
</MenuItem>
|
||||
<Divider />
|
||||
<MenuItem sx={{ py: 2 }} onClick={() => handleDropdownClose('/pages/login')}>
|
||||
<LogoutVariant sx={{ marginRight: 2, fontSize: '1.375rem', color: 'text.secondary' }} />
|
||||
Logout
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserDropdown;
|
@@ -0,0 +1,53 @@
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box';
|
||||
import Link from '@mui/material/Link';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
|
||||
const FooterContent = () => {
|
||||
// ** Var
|
||||
const hidden = useMediaQuery(theme => theme.breakpoints.down('md'));
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Typography sx={{ mr: 2 }}>
|
||||
{`© ${new Date().getFullYear()}, Made with `}
|
||||
<Box component="span" sx={{ color: 'error.main' }}>
|
||||
❤️
|
||||
</Box>
|
||||
{` by `}
|
||||
<Link target="_blank" href="https://themeselection.com/">
|
||||
ThemeSelection
|
||||
</Link>{' '}
|
||||
and for project
|
||||
</Typography>
|
||||
{hidden ? null : (
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', '& :not(:last-child)': { mr: 4 } }}>
|
||||
<Link
|
||||
target="_blank"
|
||||
href="https://github.com/themeselection/materio-mui-react-nextjs-admin-template-free/blob/main/LICENSE"
|
||||
>
|
||||
MIT License
|
||||
</Link>
|
||||
<Link target="_blank" href="https://themeselection.com/">
|
||||
More Themes
|
||||
</Link>
|
||||
<Link
|
||||
target="_blank"
|
||||
href="https://github.com/themeselection/materio-mui-react-nextjs-admin-template-free/blob/main/README.md"
|
||||
>
|
||||
Documentation
|
||||
</Link>
|
||||
<Link
|
||||
target="_blank"
|
||||
href="https://github.com/themeselection/materio-mui-react-nextjs-admin-template-free/issues"
|
||||
>
|
||||
Support
|
||||
</Link>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default FooterContent;
|
@@ -0,0 +1,45 @@
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
// ** Footer Content Component
|
||||
import FooterContent from './FooterContent';
|
||||
|
||||
const Footer = props => {
|
||||
// ** Props
|
||||
const { settings, footerContent: userFooterContent } = props;
|
||||
|
||||
// ** Hook
|
||||
const theme = useTheme();
|
||||
|
||||
// ** Vars
|
||||
const { contentWidth } = settings;
|
||||
|
||||
return (
|
||||
<Box
|
||||
component="footer"
|
||||
className="layout-footer"
|
||||
sx={{
|
||||
zIndex: 10,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
className="footer-content-container"
|
||||
sx={{
|
||||
width: '100%',
|
||||
borderTopLeftRadius: 14,
|
||||
borderTopRightRadius: 14,
|
||||
padding: theme.spacing(4, 6),
|
||||
...(contentWidth === 'boxed' && { '@media (min-width:1440px)': { maxWidth: 1440 } }),
|
||||
}}
|
||||
>
|
||||
{userFooterContent ? userFooterContent(props) : <FooterContent />}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
@@ -0,0 +1,56 @@
|
||||
// ** MUI Imports
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import MuiAppBar from '@mui/material/AppBar';
|
||||
import MuiToolbar from '@mui/material/Toolbar';
|
||||
|
||||
const AppBar = styled(MuiAppBar)(({ theme }) => ({
|
||||
transition: 'none',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: theme.spacing(0, 6),
|
||||
backgroundColor: 'transparent',
|
||||
color: theme.palette.text.primary,
|
||||
minHeight: theme.mixins.toolbar.minHeight,
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
paddingLeft: theme.spacing(4),
|
||||
paddingRight: theme.spacing(4),
|
||||
},
|
||||
}));
|
||||
|
||||
const Toolbar = styled(MuiToolbar)(({ theme }) => ({
|
||||
width: '100%',
|
||||
borderBottomLeftRadius: 10,
|
||||
borderBottomRightRadius: 10,
|
||||
padding: `${theme.spacing(0)} !important`,
|
||||
minHeight: `${theme.mixins.toolbar.minHeight}px !important`,
|
||||
transition:
|
||||
'padding .25s ease-in-out, box-shadow .25s ease-in-out, backdrop-filter .25s ease-in-out, background-color .25s ease-in-out',
|
||||
}));
|
||||
|
||||
const LayoutAppBar = props => {
|
||||
// ** Props
|
||||
const { settings, verticalAppBarContent: userVerticalAppBarContent } = props;
|
||||
|
||||
// ** Hooks
|
||||
const theme = useTheme();
|
||||
|
||||
// ** Vars
|
||||
const { contentWidth } = settings;
|
||||
|
||||
return (
|
||||
<AppBar elevation={0} color="default" className="layout-navbar" position="static">
|
||||
<Toolbar
|
||||
className="navbar-content-container"
|
||||
sx={{
|
||||
...(contentWidth === 'boxed' && {
|
||||
'@media (min-width:1440px)': { maxWidth: `calc(1440px - ${theme.spacing(6)} * 2)` },
|
||||
}),
|
||||
}}
|
||||
>
|
||||
{(userVerticalAppBarContent && userVerticalAppBarContent(props)) || null}
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
);
|
||||
};
|
||||
|
||||
export default LayoutAppBar;
|
@@ -0,0 +1,66 @@
|
||||
// ** MUI Imports
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import MuiSwipeableDrawer from '@mui/material/SwipeableDrawer';
|
||||
|
||||
const SwipeableDrawer = styled(MuiSwipeableDrawer)({
|
||||
overflowX: 'hidden',
|
||||
transition: 'width .25s ease-in-out',
|
||||
'& ul': {
|
||||
listStyle: 'none',
|
||||
},
|
||||
'& .MuiListItem-gutters': {
|
||||
paddingLeft: 4,
|
||||
paddingRight: 4,
|
||||
},
|
||||
'& .MuiDrawer-paper': {
|
||||
left: 'unset',
|
||||
right: 'unset',
|
||||
overflowX: 'hidden',
|
||||
transition: 'width .25s ease-in-out, box-shadow .25s ease-in-out',
|
||||
},
|
||||
});
|
||||
|
||||
const Drawer = props => {
|
||||
// ** Props
|
||||
const { hidden, children, navWidth, navVisible, setNavVisible } = props;
|
||||
|
||||
// ** Hook
|
||||
const theme = useTheme();
|
||||
|
||||
// Drawer Props for Mobile & Tablet screens
|
||||
const MobileDrawerProps = {
|
||||
open: navVisible,
|
||||
onOpen: () => setNavVisible(true),
|
||||
onClose: () => setNavVisible(false),
|
||||
ModalProps: {
|
||||
keepMounted: true, // Better open performance on mobile.
|
||||
},
|
||||
};
|
||||
|
||||
// Drawer Props for Desktop screens
|
||||
const DesktopDrawerProps = {
|
||||
open: true,
|
||||
onOpen: () => null,
|
||||
onClose: () => null,
|
||||
};
|
||||
|
||||
return (
|
||||
<SwipeableDrawer
|
||||
className="layout-vertical-nav"
|
||||
variant={hidden ? 'temporary' : 'permanent'}
|
||||
{...(hidden ? { ...MobileDrawerProps } : { ...DesktopDrawerProps })}
|
||||
PaperProps={{ sx: { width: navWidth } }}
|
||||
sx={{
|
||||
width: navWidth,
|
||||
'& .MuiDrawer-paper': {
|
||||
borderRight: 0,
|
||||
backgroundColor: theme.palette.background.default,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</SwipeableDrawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Drawer;
|
@@ -0,0 +1,119 @@
|
||||
// ** Next Import
|
||||
import Link from 'next/link';
|
||||
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box';
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
// ** Configs
|
||||
import themeConfig from 'src/configs/themeConfig';
|
||||
|
||||
// ** Styled Components
|
||||
const MenuHeaderWrapper = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingRight: theme.spacing(4.5),
|
||||
transition: 'padding .25s ease-in-out',
|
||||
minHeight: theme.mixins.toolbar.minHeight,
|
||||
}));
|
||||
|
||||
const HeaderTitle = styled(Typography)(({ theme }) => ({
|
||||
fontWeight: 600,
|
||||
lineHeight: 'normal',
|
||||
textTransform: 'uppercase',
|
||||
color: theme.palette.text.primary,
|
||||
transition: 'opacity .25s ease-in-out, margin .25s ease-in-out',
|
||||
}));
|
||||
|
||||
const StyledLink = styled('a')({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
textDecoration: 'none',
|
||||
});
|
||||
|
||||
const VerticalNavHeader = props => {
|
||||
// ** Props
|
||||
const { verticalNavMenuBranding: userVerticalNavMenuBranding } = props;
|
||||
|
||||
// ** Hooks
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<MenuHeaderWrapper className="nav-header" sx={{ pl: 6 }}>
|
||||
{userVerticalNavMenuBranding ? (
|
||||
userVerticalNavMenuBranding(props)
|
||||
) : (
|
||||
<Link href="/" passHref>
|
||||
<StyledLink>
|
||||
<svg
|
||||
width={30}
|
||||
height={25}
|
||||
version="1.1"
|
||||
viewBox="0 0 30 23"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
||||
<g id="Artboard" transform="translate(-95.000000, -51.000000)">
|
||||
<g id="logo" transform="translate(95.000000, 50.000000)">
|
||||
<path
|
||||
id="Combined-Shape"
|
||||
fill={theme.palette.primary.main}
|
||||
d="M30,21.3918362 C30,21.7535219 29.9019196,22.1084381 29.7162004,22.4188007 C29.1490236,23.366632 27.9208668,23.6752135 26.9730355,23.1080366 L26.9730355,23.1080366 L23.714971,21.1584295 C23.1114106,20.7972624 22.7419355,20.1455972 22.7419355,19.4422291 L22.7419355,19.4422291 L22.741,12.7425689 L15,17.1774194 L7.258,12.7425689 L7.25806452,19.4422291 C7.25806452,20.1455972 6.88858935,20.7972624 6.28502902,21.1584295 L3.0269645,23.1080366 C2.07913318,23.6752135 0.850976404,23.366632 0.283799571,22.4188007 C0.0980803893,22.1084381 2.0190442e-15,21.7535219 0,21.3918362 L0,3.58469444 L0.00548573643,3.43543209 L0.00548573643,3.43543209 L0,3.5715689 C3.0881846e-16,2.4669994 0.8954305,1.5715689 2,1.5715689 C2.36889529,1.5715689 2.73060353,1.67359571 3.04512412,1.86636639 L15,9.19354839 L26.9548759,1.86636639 C27.2693965,1.67359571 27.6311047,1.5715689 28,1.5715689 C29.1045695,1.5715689 30,2.4669994 30,3.5715689 L30,3.5715689 Z"
|
||||
/>
|
||||
<polygon
|
||||
id="Rectangle"
|
||||
opacity="0.077704"
|
||||
fill={theme.palette.common.black}
|
||||
points="0 8.58870968 7.25806452 12.7505183 7.25806452 16.8305646"
|
||||
/>
|
||||
<polygon
|
||||
id="Rectangle"
|
||||
opacity="0.077704"
|
||||
fill={theme.palette.common.black}
|
||||
points="0 8.58870968 7.25806452 12.6445567 7.25806452 15.1370162"
|
||||
/>
|
||||
<polygon
|
||||
id="Rectangle"
|
||||
opacity="0.077704"
|
||||
fill={theme.palette.common.black}
|
||||
points="22.7419355 8.58870968 30 12.7417372 30 16.9537453"
|
||||
transform="translate(26.370968, 12.771227) scale(-1, 1) translate(-26.370968, -12.771227) "
|
||||
/>
|
||||
<polygon
|
||||
id="Rectangle"
|
||||
opacity="0.077704"
|
||||
fill={theme.palette.common.black}
|
||||
points="22.7419355 8.58870968 30 12.6409734 30 15.2601969"
|
||||
transform="translate(26.370968, 11.924453) scale(-1, 1) translate(-26.370968, -11.924453) "
|
||||
/>
|
||||
<path
|
||||
id="Rectangle"
|
||||
fillOpacity="0.15"
|
||||
fill={theme.palette.common.white}
|
||||
d="M3.04512412,1.86636639 L15,9.19354839 L15,9.19354839 L15,17.1774194 L0,8.58649679 L0,3.5715689 C3.0881846e-16,2.4669994 0.8954305,1.5715689 2,1.5715689 C2.36889529,1.5715689 2.73060353,1.67359571 3.04512412,1.86636639 Z"
|
||||
/>
|
||||
<path
|
||||
id="Rectangle"
|
||||
fillOpacity="0.35"
|
||||
fill={theme.palette.common.white}
|
||||
transform="translate(22.500000, 8.588710) scale(-1, 1) translate(-22.500000, -8.588710) "
|
||||
d="M18.0451241,1.86636639 L30,9.19354839 L30,9.19354839 L30,17.1774194 L15,8.58649679 L15,3.5715689 C15,2.4669994 15.8954305,1.5715689 17,1.5715689 C17.3688953,1.5715689 17.7306035,1.67359571 18.0451241,1.86636639 Z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<HeaderTitle variant="h6" sx={{ ml: 3 }}>
|
||||
{themeConfig.templateName}
|
||||
</HeaderTitle>
|
||||
</StyledLink>
|
||||
</Link>
|
||||
)}
|
||||
</MenuHeaderWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default VerticalNavHeader;
|
@@ -0,0 +1,24 @@
|
||||
// ** Custom Menu Components
|
||||
import VerticalNavLink from './VerticalNavLink';
|
||||
import VerticalNavSectionTitle from './VerticalNavSectionTitle';
|
||||
|
||||
const resolveNavItemComponent = item => {
|
||||
if (item.sectionTitle) return VerticalNavSectionTitle;
|
||||
|
||||
return VerticalNavLink;
|
||||
};
|
||||
|
||||
const VerticalNavItems = props => {
|
||||
// ** Props
|
||||
const { verticalNavItems } = props;
|
||||
|
||||
const RenderMenuItems = verticalNavItems?.map((item, index) => {
|
||||
const TagName = resolveNavItemComponent(item);
|
||||
|
||||
return <TagName {...props} key={index} item={item} />;
|
||||
});
|
||||
|
||||
return <>{RenderMenuItems}</>;
|
||||
};
|
||||
|
||||
export default VerticalNavItems;
|
@@ -0,0 +1,119 @@
|
||||
// ** Next Imports
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
// ** MUI Imports
|
||||
import Chip from '@mui/material/Chip';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Box from '@mui/material/Box';
|
||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||
import ListItemButton from '@mui/material/ListItemButton';
|
||||
|
||||
// ** Configs Import
|
||||
import themeConfig from 'src/configs/themeConfig';
|
||||
|
||||
// ** Custom Components Imports
|
||||
import UserIcon from 'src/layouts/components/UserIcon';
|
||||
|
||||
// ** Utils
|
||||
import { handleURLQueries } from 'src/@core/layouts/utils';
|
||||
|
||||
// ** Styled Components
|
||||
const MenuNavLink = styled(ListItemButton)(({ theme }) => ({
|
||||
width: '100%',
|
||||
borderTopRightRadius: 100,
|
||||
borderBottomRightRadius: 100,
|
||||
color: theme.palette.text.primary,
|
||||
padding: theme.spacing(2.25, 3.5),
|
||||
transition: 'opacity .25s ease-in-out',
|
||||
'&.active, &.active:hover': {
|
||||
boxShadow: theme.shadows[3],
|
||||
backgroundImage: `linear-gradient(98deg, ${theme.palette.customColors.primaryGradient}, ${theme.palette.primary.main} 94%)`,
|
||||
},
|
||||
'&.active .MuiTypography-root, &.active .MuiSvgIcon-root': {
|
||||
color: `${theme.palette.common.white} !important`,
|
||||
},
|
||||
}));
|
||||
|
||||
const MenuItemTextMetaWrapper = styled(Box)({
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
transition: 'opacity .25s ease-in-out',
|
||||
...(themeConfig.menuTextTruncate && { overflow: 'hidden' }),
|
||||
});
|
||||
|
||||
const VerticalNavLink = ({ item, navVisible, toggleNavVisibility }) => {
|
||||
// ** Hooks
|
||||
const router = useRouter();
|
||||
const IconTag = item.icon;
|
||||
|
||||
const isNavLinkActive = () => {
|
||||
if (router.pathname === item.path || handleURLQueries(router, item.path)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
disablePadding
|
||||
className="nav-link"
|
||||
disabled={item.disabled || false}
|
||||
sx={{ mt: 1.5, px: '0 !important' }}
|
||||
>
|
||||
<Link passHref href={item.path === undefined ? '/' : `${item.path}`}>
|
||||
<MenuNavLink
|
||||
component={'a'}
|
||||
className={isNavLinkActive() ? 'active' : ''}
|
||||
{...(item.openInNewTab ? { target: '_blank' } : null)}
|
||||
onClick={e => {
|
||||
if (item.path === undefined) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
if (navVisible) {
|
||||
toggleNavVisibility();
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
pl: 5.5,
|
||||
...(item.disabled ? { pointerEvents: 'none' } : { cursor: 'pointer' }),
|
||||
}}
|
||||
>
|
||||
<ListItemIcon
|
||||
sx={{
|
||||
mr: 2.5,
|
||||
color: 'text.primary',
|
||||
transition: 'margin .25s ease-in-out',
|
||||
}}
|
||||
>
|
||||
<UserIcon icon={IconTag} />
|
||||
</ListItemIcon>
|
||||
|
||||
<MenuItemTextMetaWrapper>
|
||||
<Typography {...(themeConfig.menuTextTruncate && { noWrap: true })}>{item.title}</Typography>
|
||||
{item.badgeContent ? (
|
||||
<Chip
|
||||
label={item.badgeContent}
|
||||
color={item.badgeColor || 'primary'}
|
||||
sx={{
|
||||
height: 20,
|
||||
fontWeight: 500,
|
||||
marginLeft: 1.25,
|
||||
'& .MuiChip-label': { px: 1.5, textTransform: 'capitalize' },
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</MenuItemTextMetaWrapper>
|
||||
</MenuNavLink>
|
||||
</Link>
|
||||
</ListItem>
|
||||
);
|
||||
};
|
||||
|
||||
export default VerticalNavLink;
|
@@ -0,0 +1,63 @@
|
||||
// ** MUI Imports
|
||||
import Divider from '@mui/material/Divider';
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import MuiListSubheader from '@mui/material/ListSubheader';
|
||||
|
||||
// ** Styled Components
|
||||
const ListSubheader = styled(props => <MuiListSubheader component="li" {...props} />)(({ theme }) => ({
|
||||
lineHeight: 1,
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
marginTop: theme.spacing(7),
|
||||
marginBottom: theme.spacing(2),
|
||||
backgroundColor: 'transparent',
|
||||
transition: 'padding-left .25s ease-in-out',
|
||||
}));
|
||||
|
||||
const TypographyHeaderText = styled(Typography)(({ theme }) => ({
|
||||
fontSize: '0.75rem',
|
||||
lineHeight: 'normal',
|
||||
letterSpacing: '0.21px',
|
||||
textTransform: 'uppercase',
|
||||
color: theme.palette.text.disabled,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
}));
|
||||
|
||||
const VerticalNavSectionTitle = props => {
|
||||
// ** Props
|
||||
const { item } = props;
|
||||
|
||||
// ** Hook
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<ListSubheader
|
||||
className="nav-section-title"
|
||||
sx={{
|
||||
px: 0,
|
||||
py: 1.75,
|
||||
color: theme.palette.text.disabled,
|
||||
'& .MuiDivider-root:before, & .MuiDivider-root:after, & hr': {
|
||||
borderColor: `rgba(${theme.palette.customColors.main}, 0.12)`,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Divider
|
||||
textAlign="left"
|
||||
sx={{
|
||||
m: 0,
|
||||
width: '100%',
|
||||
lineHeight: 'normal',
|
||||
textTransform: 'uppercase',
|
||||
'&:before, &:after': { top: 7, transform: 'none' },
|
||||
'& .MuiDivider-wrapper': { px: 2.5, fontSize: '0.75rem', letterSpacing: '0.21px' },
|
||||
}}
|
||||
>
|
||||
<TypographyHeaderText noWrap>{item.sectionTitle}</TypographyHeaderText>
|
||||
</Divider>
|
||||
</ListSubheader>
|
||||
);
|
||||
};
|
||||
|
||||
export default VerticalNavSectionTitle;
|
@@ -0,0 +1,131 @@
|
||||
// ** React Import
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
// ** MUI Import
|
||||
import List from '@mui/material/List';
|
||||
import Box from '@mui/material/Box';
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
|
||||
// ** Third Party Components
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar';
|
||||
|
||||
// ** Component Imports
|
||||
import Drawer from './Drawer';
|
||||
import VerticalNavItems from './VerticalNavItems';
|
||||
import VerticalNavHeader from './VerticalNavHeader';
|
||||
|
||||
// ** Util Import
|
||||
import { hexToRGBA } from 'src/@core/utils/hex-to-rgba';
|
||||
|
||||
const StyledBoxForShadow = styled(Box)({
|
||||
top: 50,
|
||||
left: -8,
|
||||
zIndex: 2,
|
||||
height: 75,
|
||||
display: 'none',
|
||||
position: 'absolute',
|
||||
pointerEvents: 'none',
|
||||
width: 'calc(100% + 15px)',
|
||||
'&.d-block': {
|
||||
display: 'block',
|
||||
},
|
||||
});
|
||||
|
||||
const Navigation = props => {
|
||||
// ** Props
|
||||
const {
|
||||
hidden,
|
||||
afterVerticalNavMenuContent,
|
||||
beforeVerticalNavMenuContent,
|
||||
verticalNavMenuContent: userVerticalNavMenuContent,
|
||||
} = props;
|
||||
|
||||
// ** States
|
||||
const [groupActive, setGroupActive] = useState([]);
|
||||
const [currentActiveGroup, setCurrentActiveGroup] = useState([]);
|
||||
|
||||
// ** Ref
|
||||
const shadowRef = useRef(null);
|
||||
|
||||
// ** Hooks
|
||||
const theme = useTheme();
|
||||
|
||||
// ** Fixes Navigation InfiniteScroll
|
||||
const handleInfiniteScroll = ref => {
|
||||
if (ref) {
|
||||
// @ts-ignore
|
||||
ref._getBoundingClientRect = ref.getBoundingClientRect;
|
||||
ref.getBoundingClientRect = () => {
|
||||
// @ts-ignore
|
||||
const original = ref._getBoundingClientRect();
|
||||
|
||||
return { ...original, height: Math.floor(original.height) };
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// ** Scroll Menu
|
||||
const scrollMenu = container => {
|
||||
container = hidden ? container.target : container;
|
||||
if (shadowRef && container.scrollTop > 0) {
|
||||
// @ts-ignore
|
||||
if (!shadowRef.current.classList.contains('d-block')) {
|
||||
// @ts-ignore
|
||||
shadowRef.current.classList.add('d-block');
|
||||
}
|
||||
} else {
|
||||
// @ts-ignore
|
||||
shadowRef.current.classList.remove('d-block');
|
||||
}
|
||||
};
|
||||
const ScrollWrapper = hidden ? Box : PerfectScrollbar;
|
||||
|
||||
return (
|
||||
<Drawer {...props}>
|
||||
<VerticalNavHeader {...props} />
|
||||
<StyledBoxForShadow
|
||||
ref={shadowRef}
|
||||
sx={{
|
||||
background: `linear-gradient(${theme.palette.background.default} 40%,${hexToRGBA(
|
||||
theme.palette.background.default,
|
||||
0.1,
|
||||
)} 95%,${hexToRGBA(theme.palette.background.default, 0.05)})`,
|
||||
}}
|
||||
/>
|
||||
<Box sx={{ height: '100%', position: 'relative', overflow: 'hidden' }}>
|
||||
<ScrollWrapper
|
||||
containerRef={ref => handleInfiniteScroll(ref)}
|
||||
{...(hidden
|
||||
? {
|
||||
onScroll: container => scrollMenu(container),
|
||||
sx: { height: '100%', overflowY: 'auto', overflowX: 'hidden' },
|
||||
}
|
||||
: {
|
||||
options: { wheelPropagation: false },
|
||||
onScrollY: container => scrollMenu(container),
|
||||
})}
|
||||
>
|
||||
{beforeVerticalNavMenuContent ? beforeVerticalNavMenuContent(props) : null}
|
||||
<Box sx={{ height: '100%', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
|
||||
{userVerticalNavMenuContent ? (
|
||||
userVerticalNavMenuContent(props)
|
||||
) : (
|
||||
<List className="nav-items" sx={{ transition: 'padding .25s ease', pr: 4.5 }}>
|
||||
<VerticalNavItems
|
||||
groupActive={groupActive}
|
||||
setGroupActive={setGroupActive}
|
||||
currentActiveGroup={currentActiveGroup}
|
||||
setCurrentActiveGroup={setCurrentActiveGroup}
|
||||
{...props}
|
||||
/>
|
||||
</List>
|
||||
)}
|
||||
</Box>
|
||||
</ScrollWrapper>
|
||||
</Box>
|
||||
{afterVerticalNavMenuContent ? afterVerticalNavMenuContent(props) : null}
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navigation;
|
16
tsc1877/task1/aws/workspace/admin/src/@core/layouts/utils.js
Normal file
16
tsc1877/task1/aws/workspace/admin/src/@core/layouts/utils.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Check for URL queries as well for matching
|
||||
* Current URL & Item Path
|
||||
*
|
||||
* @param item
|
||||
* @param activeItem
|
||||
*/
|
||||
export const handleURLQueries = (router, path) => {
|
||||
if (Object.keys(router.query).length && path) {
|
||||
const arr = Object.keys(router.query);
|
||||
|
||||
return router.asPath.includes(path) && router.asPath.includes(router.query[arr[0]]) && path !== '/';
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
103
tsc1877/task1/aws/workspace/admin/src/@core/styles/libs/react-apexcharts/index.js
vendored
Normal file
103
tsc1877/task1/aws/workspace/admin/src/@core/styles/libs/react-apexcharts/index.js
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
// ** MUI imports
|
||||
import { styled } from '@mui/material/styles';
|
||||
|
||||
const ApexChartWrapper = styled('div')(({ theme }) => ({
|
||||
'& .apexcharts-canvas': {
|
||||
"& line[stroke='transparent']": {
|
||||
display: 'none',
|
||||
},
|
||||
'& .apexcharts-xaxis > line, & .apexcharts-yaxis > line': {
|
||||
stroke: theme.palette.divider,
|
||||
},
|
||||
'& .apexcharts-xaxis-tick, & .apexcharts-yaxis-tick': {
|
||||
stroke: theme.palette.divider,
|
||||
},
|
||||
'& .apexcharts-tooltip': {
|
||||
boxShadow: theme.shadows[3],
|
||||
borderColor: theme.palette.divider,
|
||||
background: theme.palette.background.paper,
|
||||
'& .apexcharts-tooltip-title': {
|
||||
fontWeight: 600,
|
||||
borderColor: theme.palette.divider,
|
||||
background: theme.palette.background.paper,
|
||||
},
|
||||
'&.apexcharts-theme-dark': {
|
||||
'& .apexcharts-tooltip-text-label, & .apexcharts-tooltip-text-value': {
|
||||
color: theme.palette.common.white,
|
||||
},
|
||||
},
|
||||
'& .bar-chart': {
|
||||
padding: theme.spacing(2, 2.5),
|
||||
},
|
||||
},
|
||||
'& .apexcharts-xaxistooltip': {
|
||||
borderColor: theme.palette.divider,
|
||||
background: theme.palette.mode === 'light' ? theme.palette.grey[50] : theme.palette.background.default,
|
||||
'& .apexcharts-xaxistooltip-text': {
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
'&:after': {
|
||||
borderBottomColor: theme.palette.mode === 'light' ? theme.palette.grey[50] : theme.palette.background.default,
|
||||
},
|
||||
'&:before': {
|
||||
borderBottomColor: theme.palette.divider,
|
||||
},
|
||||
},
|
||||
'& .apexcharts-yaxistooltip': {
|
||||
borderColor: theme.palette.divider,
|
||||
background: theme.palette.mode === 'light' ? theme.palette.grey[50] : theme.palette.background.default,
|
||||
'& .apexcharts-yaxistooltip-text': {
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
'&:after': {
|
||||
borderLeftColor: theme.palette.mode === 'light' ? theme.palette.grey[50] : theme.palette.background.default,
|
||||
},
|
||||
'&:before': {
|
||||
borderLeftColor: theme.palette.divider,
|
||||
},
|
||||
},
|
||||
'& .apexcharts-text, & .apexcharts-tooltip-text, & .apexcharts-datalabel-label, & .apexcharts-datalabel': {
|
||||
filter: 'none',
|
||||
fontWeight: 400,
|
||||
fill: theme.palette.text.primary,
|
||||
fontFamily: `${theme.typography.fontFamily} !important`,
|
||||
},
|
||||
'& .apexcharts-pie-label': {
|
||||
filter: 'none',
|
||||
fill: theme.palette.common.white,
|
||||
},
|
||||
'& .apexcharts-pie': {
|
||||
'& .apexcharts-datalabel-label, .apexcharts-datalabel-value': {
|
||||
fontSize: '1.5rem',
|
||||
},
|
||||
},
|
||||
'& .apexcharts-marker': {
|
||||
boxShadow: 'none',
|
||||
},
|
||||
'& .apexcharts-legend-series': {
|
||||
margin: `${theme.spacing(0.75, 2)} !important`,
|
||||
'& .apexcharts-legend-text': {
|
||||
marginLeft: theme.spacing(0.75),
|
||||
color: `${theme.palette.text.primary} !important`,
|
||||
},
|
||||
},
|
||||
'& .apexcharts-xcrosshairs, & .apexcharts-ycrosshairs, & .apexcharts-gridline': {
|
||||
stroke: theme.palette.divider,
|
||||
},
|
||||
'& .apexcharts-heatmap-rect': {
|
||||
stroke: theme.palette.mode === 'light' ? theme.palette.background.paper : theme.palette.background.default,
|
||||
},
|
||||
'& .apexcharts-radialbar > g > g:first-of-type .apexcharts-radialbar-area': {
|
||||
stroke: theme.palette.background.default,
|
||||
},
|
||||
'& .apexcharts-radar-series polygon': {
|
||||
stroke: theme.palette.divider,
|
||||
fill: theme.palette.background.paper,
|
||||
},
|
||||
'& .apexcharts-radar-series line': {
|
||||
stroke: theme.palette.divider,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export default ApexChartWrapper;
|
358
tsc1877/task1/aws/workspace/admin/src/@core/styles/libs/react-datepicker/index.js
vendored
Normal file
358
tsc1877/task1/aws/workspace/admin/src/@core/styles/libs/react-datepicker/index.js
vendored
Normal file
@@ -0,0 +1,358 @@
|
||||
// ** MUI imports
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
// ** Util Import
|
||||
import { hexToRGBA } from 'src/@core/utils/hex-to-rgba';
|
||||
|
||||
const DatePickerWrapper = styled(Box)(({ theme }) => {
|
||||
return {
|
||||
'& .react-datepicker-popper': {
|
||||
zIndex: 5,
|
||||
},
|
||||
'& .react-datepicker-wrapper': {
|
||||
width: '100%',
|
||||
},
|
||||
'& .react-datepicker': {
|
||||
border: 'none',
|
||||
boxShadow: theme.shadows[7],
|
||||
padding: theme.spacing(2, 0),
|
||||
color: theme.palette.text.primary,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
fontFamily: theme.typography.fontFamily,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
'& .react-datepicker__header': {
|
||||
padding: 0,
|
||||
border: 'none',
|
||||
fontWeight: 'normal',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
'& .react-datepicker__day-name': {
|
||||
margin: 0,
|
||||
},
|
||||
},
|
||||
'& .react-datepicker-year-header': {
|
||||
lineHeight: 2.1,
|
||||
marginBottom: '0.5rem',
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
'& .react-datepicker__triangle': {
|
||||
display: 'none',
|
||||
},
|
||||
'& > .react-datepicker__navigation': {
|
||||
top: theme.spacing(3),
|
||||
'&.react-datepicker__navigation--previous': {
|
||||
border: 'none',
|
||||
backgroundImage: `${"url('data:image/svg+xml,%3Csvg xmlns=\\'http://www.w3.org/2000/svg\\' style=\\'width:24px;height:24px\\' viewBox=\\'0 0 24 24\\'%3E%3Cpath fill=\\'currentColor\\' d=\\'M15.41,16.58L10.83,12L15.41,7.41L14,6L8,12L14,18L15.41,16.58Z\\' /%3E%3C/svg%3E')"
|
||||
.replace('currentColor', theme.palette.text.secondary)
|
||||
.replace('#', '%23')}`,
|
||||
height: '24px',
|
||||
width: '24px',
|
||||
'& .react-datepicker__navigation-icon': {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
'&.react-datepicker__navigation--next': {
|
||||
border: 'none',
|
||||
backgroundImage: `${"url('data:image/svg+xml,%3Csvg xmlns=\\'http://www.w3.org/2000/svg\\' style=\\'width:24px;height:24px\\' viewBox=\\'0 0 24 24\\'%3E%3Cpath fill=\\'currentColor\\' d=\\'M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z\\' /%3E%3C/svg%3E')"
|
||||
.replace('currentColor', theme.palette.text.secondary)
|
||||
.replace('#', '%23')}`,
|
||||
height: '24px',
|
||||
width: '24px',
|
||||
'& .react-datepicker__navigation-icon': {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
'&.react-datepicker__navigation--next--with-time': {
|
||||
right: '122px',
|
||||
},
|
||||
'&:focus, &:active': {
|
||||
outline: 0,
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__current-month': {
|
||||
lineHeight: 2.1,
|
||||
fontSize: '1rem',
|
||||
fontWeight: 'normal',
|
||||
letterSpacing: '0.15px',
|
||||
marginBottom: theme.spacing(2),
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
'& .react-datepicker__day-name': {
|
||||
lineHeight: 1.5,
|
||||
width: '2.25rem',
|
||||
fontSize: '0.75rem',
|
||||
letterSpacing: '0.4px',
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
'& .react-datepicker__day': {
|
||||
margin: 0,
|
||||
width: '2.25rem',
|
||||
lineHeight: 2.75,
|
||||
height: '2.25rem',
|
||||
borderRadius: '50%',
|
||||
color: theme.palette.text.primary,
|
||||
'&.react-datepicker__day--selected, &.react-datepicker__day--keyboard-selected': {
|
||||
color: theme.palette.common.white,
|
||||
backgroundColor: `${theme.palette.primary.main} !important`,
|
||||
},
|
||||
'&.react-datepicker__day--in-range, &.react-datepicker__day--in-selecting-range': {
|
||||
borderRadius: 0,
|
||||
color: theme.palette.primary.main,
|
||||
backgroundColor: `${hexToRGBA(theme.palette.primary.main, 0.06)} !important`,
|
||||
'&:empty': {
|
||||
backgroundColor: 'transparent !important',
|
||||
},
|
||||
},
|
||||
'&.react-datepicker__day--selected.react-datepicker__day--in-selecting-range.react-datepicker__day--selecting-range-start, &.react-datepicker__day--selected.react-datepicker__day--range-start.react-datepicker__day--in-range, &.react-datepicker__day--range-start':
|
||||
{
|
||||
borderTopLeftRadius: '50%',
|
||||
borderBottomLeftRadius: '50%',
|
||||
color: theme.palette.common.white,
|
||||
backgroundColor: `${theme.palette.primary.main} !important`,
|
||||
},
|
||||
'&.react-datepicker__day--range-end': {
|
||||
borderTopRightRadius: '50%',
|
||||
borderBottomRightRadius: '50%',
|
||||
color: theme.palette.common.white,
|
||||
backgroundColor: `${theme.palette.primary.main} !important`,
|
||||
},
|
||||
'&:focus, &:active': {
|
||||
outline: 0,
|
||||
},
|
||||
'&.react-datepicker__day--outside-month': {
|
||||
height: 'auto',
|
||||
},
|
||||
'&.react-datepicker__day--outside-month, &.react-datepicker__day--disabled:not(.react-datepicker__day--selected)':
|
||||
{
|
||||
color: theme.palette.text.disabled,
|
||||
'&:hover': {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
},
|
||||
'&.react-datepicker__day--highlighted, &.react-datepicker__day--highlighted:hover': {
|
||||
color: theme.palette.success.main,
|
||||
backgroundColor: hexToRGBA(theme.palette.success.main, 0.12),
|
||||
},
|
||||
'&.react-datepicker__day--today': {
|
||||
fontWeight: 'normal',
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__header__dropdown': {
|
||||
'& .react-datepicker__month-dropdown-container:not(:last-child)': {
|
||||
marginRight: theme.spacing(8),
|
||||
},
|
||||
'& .react-datepicker__month-dropdown-container, & .react-datepicker__year-dropdown-container': {
|
||||
marginBottom: theme.spacing(4),
|
||||
},
|
||||
'& .react-datepicker__month-read-view--selected-month, & .react-datepicker__year-read-view--selected-year': {
|
||||
fontSize: '0.875rem',
|
||||
marginRight: theme.spacing(1),
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
'& .react-datepicker__month-read-view:hover .react-datepicker__month-read-view--down-arrow, & .react-datepicker__year-read-view:hover .react-datepicker__year-read-view--down-arrow':
|
||||
{
|
||||
borderTopColor: theme.palette.text.secondary,
|
||||
borderRightColor: theme.palette.text.secondary,
|
||||
},
|
||||
'& .react-datepicker__month-read-view--down-arrow, & .react-datepicker__year-read-view--down-arrow': {
|
||||
top: 4,
|
||||
borderTopColor: theme.palette.text.disabled,
|
||||
borderRightColor: theme.palette.text.disabled,
|
||||
},
|
||||
'& .react-datepicker__month-dropdown, & .react-datepicker__year-dropdown': {
|
||||
paddingTop: theme.spacing(1.5),
|
||||
paddingBottom: theme.spacing(1.5),
|
||||
borderColor: theme.palette.divider,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
boxShadow: theme.palette.mode === 'light' ? theme.shadows[8] : theme.shadows[9],
|
||||
},
|
||||
'& .react-datepicker__month-option, & .react-datepicker__year-option': {
|
||||
paddingTop: theme.spacing(0.5),
|
||||
paddingBottom: theme.spacing(0.5),
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action.hover,
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__month-option.react-datepicker__month-option--selected_month': {
|
||||
backgroundColor: hexToRGBA(theme.palette.primary.main, 0.08),
|
||||
'&:hover': {
|
||||
backgroundColor: hexToRGBA(theme.palette.primary.main, 0.12),
|
||||
},
|
||||
'& .react-datepicker__month-option--selected': {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__year-option.react-datepicker__year-option--selected_year': {
|
||||
backgroundColor: hexToRGBA(theme.palette.primary.main, 0.08),
|
||||
'&:hover': {
|
||||
backgroundColor: hexToRGBA(theme.palette.primary.main, 0.12),
|
||||
},
|
||||
'& .react-datepicker__year-option--selected': {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__year-option': {
|
||||
// TODO: Remove some of the following styles for arrow in Year dropdown when react-datepicker give arrows in Year dropdown
|
||||
'& .react-datepicker__navigation--years-upcoming': {
|
||||
width: 9,
|
||||
height: 9,
|
||||
borderStyle: 'solid',
|
||||
borderWidth: '3px 3px 0 0',
|
||||
transform: 'rotate(-45deg)',
|
||||
borderTopColor: theme.palette.text.disabled,
|
||||
borderRightColor: theme.palette.text.disabled,
|
||||
margin: `${theme.spacing(2.75)} auto ${theme.spacing(0)}`,
|
||||
},
|
||||
'&:hover .react-datepicker__navigation--years-upcoming': {
|
||||
borderTopColor: theme.palette.text.secondary,
|
||||
borderRightColor: theme.palette.text.secondary,
|
||||
},
|
||||
'& .react-datepicker__navigation--years-previous': {
|
||||
width: 9,
|
||||
height: 9,
|
||||
borderStyle: 'solid',
|
||||
borderWidth: '0 0 3px 3px',
|
||||
transform: 'rotate(-45deg)',
|
||||
borderLeftColor: theme.palette.text.disabled,
|
||||
borderBottomColor: theme.palette.text.disabled,
|
||||
margin: `${theme.spacing(0)} auto ${theme.spacing(2.75)}`,
|
||||
},
|
||||
'&:hover .react-datepicker__navigation--years-previous': {
|
||||
borderLeftColor: theme.palette.text.secondary,
|
||||
borderBottomColor: theme.palette.text.secondary,
|
||||
},
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__month': {
|
||||
marginTop: theme.spacing(3),
|
||||
},
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
'& .react-datepicker__month': {
|
||||
marginLeft: 0,
|
||||
marginRight: 0,
|
||||
marginBottom: 0,
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__month, & .react-datepicker__year': {
|
||||
'& .react-datepicker__month-text, & .react-datepicker__year-text, & .react-datepicker__quarter-text': {
|
||||
height: '2rem',
|
||||
alignItems: 'center',
|
||||
display: 'inline-flex',
|
||||
justifyContent: 'center',
|
||||
'&:hover': {
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
'&:focus, &:active': {
|
||||
outline: 0,
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__quarter--selected, & .react-datepicker__year-text--selected, & .react-datepicker__month--selected, & .react-datepicker__quarter-text--keyboard-selected, & .react-datepicker__month-text--keyboard-selected, & .react-datepicker__year-text--keyboard-selected':
|
||||
{
|
||||
color: theme.palette.common.white,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: `${theme.palette.primary.main} !important`,
|
||||
},
|
||||
'& .react-datepicker__week-number': {
|
||||
fontWeight: 600,
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__year-wrapper': {
|
||||
maxWidth: 205,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
'& .react-datepicker__input-time-container': {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
'& .react-datepicker__today-button': {
|
||||
borderRadius: '1rem',
|
||||
margin: '0 1rem 0.3rem',
|
||||
color: theme.palette.common.white,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
|
||||
// ** Time Picker
|
||||
'& .react-datepicker__time-container': {
|
||||
borderLeftColor: theme.palette.divider,
|
||||
},
|
||||
'&.react-datepicker--time-only, & .react-datepicker__time-container': {
|
||||
width: '7rem',
|
||||
padding: theme.spacing(1.2, 0),
|
||||
'& .react-datepicker-time__header': {
|
||||
marginBottom: theme.spacing(3),
|
||||
color: theme.palette.text.primary,
|
||||
fontSize: theme.typography.body2.fontSize,
|
||||
},
|
||||
'& .react-datepicker__time': {
|
||||
background: theme.palette.background.paper,
|
||||
'& .react-datepicker__time-box .react-datepicker__time-list-item--disabled': {
|
||||
color: theme.palette.text.disabled,
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__time-list-item': {
|
||||
lineHeight: 1.75,
|
||||
height: 'auto !important',
|
||||
marginLeft: theme.spacing(3.2),
|
||||
marginRight: theme.spacing(1.2),
|
||||
color: theme.palette.text.primary,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
'&:focus, &:active': {
|
||||
outline: 0,
|
||||
},
|
||||
'&:hover': {
|
||||
backgroundColor: `${theme.palette.action.hover} !important`,
|
||||
},
|
||||
'&.react-datepicker__time-list-item--selected': {
|
||||
color: `${theme.palette.common.white} !important`,
|
||||
backgroundColor: `${theme.palette.primary.main} !important`,
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__time-box': {
|
||||
width: '100%',
|
||||
},
|
||||
'& .react-datepicker__time-list': {
|
||||
'&::-webkit-scrollbar': {
|
||||
width: 8,
|
||||
},
|
||||
|
||||
/* Track */
|
||||
'&::-webkit-scrollbar-track': {
|
||||
background: theme.palette.background.paper,
|
||||
},
|
||||
|
||||
/* Handle */
|
||||
'&::-webkit-scrollbar-thumb': {
|
||||
background: '#aaa',
|
||||
borderRadius: '10px',
|
||||
},
|
||||
|
||||
/* Handle on hover */
|
||||
'&::-webkit-scrollbar-thumb:hover': {
|
||||
background: '#999',
|
||||
},
|
||||
},
|
||||
},
|
||||
'&.react-datepicker--time-only .react-datepicker__time-container': {
|
||||
width: 'calc(7rem - 2px)',
|
||||
},
|
||||
'& .react-datepicker__day:hover, & .react-datepicker__month-text:hover, & .react-datepicker__quarter-text:hover, & .react-datepicker__year-text:hover':
|
||||
{
|
||||
backgroundColor: theme.palette.action.hover,
|
||||
},
|
||||
},
|
||||
'& .react-datepicker__close-icon': {
|
||||
paddingRight: theme.spacing(4),
|
||||
'&:after': {
|
||||
width: 'unset',
|
||||
height: 'unset',
|
||||
fontSize: '1.5rem',
|
||||
color: theme.palette.text.primary,
|
||||
backgroundColor: 'transparent !important',
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export default DatePickerWrapper;
|
@@ -0,0 +1,49 @@
|
||||
// ** MUI Imports
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import GlobalStyles from '@mui/material/GlobalStyles';
|
||||
import { ThemeProvider, createTheme, responsiveFontSizes } from '@mui/material/styles';
|
||||
|
||||
// ** Theme Config
|
||||
import themeConfig from 'src/configs/themeConfig';
|
||||
|
||||
// ** Theme Override Imports
|
||||
import overrides from './overrides';
|
||||
import typography from './typography';
|
||||
|
||||
// ** Theme
|
||||
import themeOptions from './ThemeOptions';
|
||||
|
||||
// ** Global Styles
|
||||
import GlobalStyling from './globalStyles';
|
||||
|
||||
const ThemeComponent = props => {
|
||||
// ** Props
|
||||
const { settings, children } = props;
|
||||
|
||||
// ** Merged ThemeOptions of Core and User
|
||||
const coreThemeConfig = themeOptions(settings);
|
||||
|
||||
// ** Pass ThemeOptions to CreateTheme Function to create partial theme without component overrides
|
||||
let theme = createTheme(coreThemeConfig);
|
||||
|
||||
// ** Continue theme creation and pass merged component overrides to CreateTheme function
|
||||
theme = createTheme(theme, {
|
||||
components: { ...overrides(theme) },
|
||||
typography: { ...typography(theme) },
|
||||
});
|
||||
|
||||
// ** Set responsive font sizes to true
|
||||
if (themeConfig.responsiveFontSizes) {
|
||||
theme = responsiveFontSizes(theme);
|
||||
}
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<GlobalStyles styles={() => GlobalStyling(theme)} />
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemeComponent;
|
@@ -0,0 +1,54 @@
|
||||
// ** MUI Theme Provider
|
||||
import { deepmerge } from '@mui/utils';
|
||||
|
||||
// ** Theme Override Imports
|
||||
import palette from './palette';
|
||||
import spacing from './spacing';
|
||||
import shadows from './shadows';
|
||||
import breakpoints from './breakpoints';
|
||||
|
||||
const themeOptions = settings => {
|
||||
// ** Vars
|
||||
const { mode, themeColor } = settings;
|
||||
|
||||
const themeConfig = {
|
||||
palette: palette(mode, themeColor),
|
||||
typography: {
|
||||
fontFamily: [
|
||||
'Inter',
|
||||
'sans-serif',
|
||||
'-apple-system',
|
||||
'BlinkMacSystemFont',
|
||||
'"Segoe UI"',
|
||||
'Roboto',
|
||||
'"Helvetica Neue"',
|
||||
'Arial',
|
||||
'sans-serif',
|
||||
'"Apple Color Emoji"',
|
||||
'"Segoe UI Emoji"',
|
||||
'"Segoe UI Symbol"',
|
||||
].join(','),
|
||||
},
|
||||
shadows: shadows(mode),
|
||||
...spacing,
|
||||
breakpoints: breakpoints(),
|
||||
shape: {
|
||||
borderRadius: 6,
|
||||
},
|
||||
mixins: {
|
||||
toolbar: {
|
||||
minHeight: 64,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return deepmerge(themeConfig, {
|
||||
palette: {
|
||||
primary: {
|
||||
...themeConfig.palette[themeColor],
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export default themeOptions;
|
@@ -0,0 +1,11 @@
|
||||
const breakpoints = () => ({
|
||||
values: {
|
||||
xs: 0,
|
||||
sm: 600,
|
||||
md: 900,
|
||||
lg: 1200,
|
||||
xl: 1536,
|
||||
},
|
||||
});
|
||||
|
||||
export default breakpoints;
|
@@ -0,0 +1,43 @@
|
||||
const GlobalStyles = theme => {
|
||||
return {
|
||||
'.ps__rail-y': {
|
||||
zIndex: 1,
|
||||
right: '0 !important',
|
||||
left: 'auto !important',
|
||||
'&:hover, &:focus, &.ps--clicking': {
|
||||
backgroundColor: theme.palette.mode === 'light' ? '#E4E5EB !important' : '#423D5D !important',
|
||||
},
|
||||
'& .ps__thumb-y': {
|
||||
right: '3px !important',
|
||||
left: 'auto !important',
|
||||
backgroundColor: theme.palette.mode === 'light' ? '#C2C4D1 !important' : '#504B6D !important',
|
||||
},
|
||||
'.layout-vertical-nav &': {
|
||||
'& .ps__thumb-y': {
|
||||
width: 4,
|
||||
backgroundColor: theme.palette.mode === 'light' ? '#C2C4D1 !important' : '#504B6D !important',
|
||||
},
|
||||
'&:hover, &:focus, &.ps--clicking': {
|
||||
backgroundColor: 'transparent !important',
|
||||
'& .ps__thumb-y': {
|
||||
width: 6,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'#nprogress': {
|
||||
pointerEvents: 'none',
|
||||
'& .bar': {
|
||||
left: 0,
|
||||
top: 0,
|
||||
height: 3,
|
||||
width: '100%',
|
||||
zIndex: 2000,
|
||||
position: 'fixed',
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default GlobalStyles;
|
@@ -0,0 +1,46 @@
|
||||
const Accordion = theme => {
|
||||
return {
|
||||
MuiAccordion: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.Mui-disabled': {
|
||||
backgroundColor: `rgba(${theme.palette.customColors.main}, 0.12)`,
|
||||
},
|
||||
'&.Mui-expanded': {
|
||||
boxShadow: theme.shadows[3],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAccordionSummary: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: `0 ${theme.spacing(5)}`,
|
||||
'& + .MuiCollapse-root': {
|
||||
'& .MuiAccordionDetails-root:first-child': {
|
||||
paddingTop: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
content: {
|
||||
margin: `${theme.spacing(2.5)} 0`,
|
||||
},
|
||||
expandIconWrapper: {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAccordionDetails: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(5),
|
||||
'& + .MuiAccordionDetails-root': {
|
||||
paddingTop: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Accordion;
|
@@ -0,0 +1,110 @@
|
||||
import { lighten, darken } from '@mui/material/styles';
|
||||
|
||||
// ** Util Import
|
||||
import { hexToRGBA } from 'src/@core/utils/hex-to-rgba';
|
||||
|
||||
const Alert = theme => {
|
||||
const getColor = theme.palette.mode === 'light' ? darken : lighten;
|
||||
|
||||
return {
|
||||
MuiAlert: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 5,
|
||||
'& .MuiAlertTitle-root': {
|
||||
marginBottom: theme.spacing(1.6),
|
||||
},
|
||||
'& a': {
|
||||
color: 'inherit',
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
standardSuccess: {
|
||||
color: getColor(theme.palette.success.main, 0.12),
|
||||
backgroundColor: hexToRGBA(theme.palette.success.main, 0.12),
|
||||
'& .MuiAlertTitle-root': {
|
||||
color: getColor(theme.palette.success.main, 0.12),
|
||||
},
|
||||
'& .MuiAlert-icon': {
|
||||
color: getColor(theme.palette.success.main, 0.12),
|
||||
},
|
||||
},
|
||||
standardInfo: {
|
||||
color: getColor(theme.palette.info.main, 0.12),
|
||||
backgroundColor: hexToRGBA(theme.palette.info.main, 0.12),
|
||||
'& .MuiAlertTitle-root': {
|
||||
color: getColor(theme.palette.info.main, 0.12),
|
||||
},
|
||||
'& .MuiAlert-icon': {
|
||||
color: getColor(theme.palette.info.main, 0.12),
|
||||
},
|
||||
},
|
||||
standardWarning: {
|
||||
color: getColor(theme.palette.warning.main, 0.12),
|
||||
backgroundColor: hexToRGBA(theme.palette.warning.main, 0.12),
|
||||
'& .MuiAlertTitle-root': {
|
||||
color: getColor(theme.palette.warning.main, 0.12),
|
||||
},
|
||||
'& .MuiAlert-icon': {
|
||||
color: getColor(theme.palette.warning.main, 0.12),
|
||||
},
|
||||
},
|
||||
standardError: {
|
||||
color: getColor(theme.palette.error.main, 0.12),
|
||||
backgroundColor: hexToRGBA(theme.palette.error.main, 0.12),
|
||||
'& .MuiAlertTitle-root': {
|
||||
color: getColor(theme.palette.error.main, 0.12),
|
||||
},
|
||||
'& .MuiAlert-icon': {
|
||||
color: getColor(theme.palette.error.main, 0.12),
|
||||
},
|
||||
},
|
||||
outlinedSuccess: {
|
||||
borderColor: theme.palette.success.main,
|
||||
color: getColor(theme.palette.success.main, 0.12),
|
||||
'& .MuiAlertTitle-root': {
|
||||
color: getColor(theme.palette.success.main, 0.12),
|
||||
},
|
||||
'& .MuiAlert-icon': {
|
||||
color: getColor(theme.palette.success.main, 0.12),
|
||||
},
|
||||
},
|
||||
outlinedInfo: {
|
||||
borderColor: theme.palette.info.main,
|
||||
color: getColor(theme.palette.info.main, 0.12),
|
||||
'& .MuiAlertTitle-root': {
|
||||
color: getColor(theme.palette.info.main, 0.12),
|
||||
},
|
||||
'& .MuiAlert-icon': {
|
||||
color: getColor(theme.palette.info.main, 0.12),
|
||||
},
|
||||
},
|
||||
outlinedWarning: {
|
||||
borderColor: theme.palette.warning.main,
|
||||
color: getColor(theme.palette.warning.main, 0.12),
|
||||
'& .MuiAlertTitle-root': {
|
||||
color: getColor(theme.palette.warning.main, 0.12),
|
||||
},
|
||||
'& .MuiAlert-icon': {
|
||||
color: getColor(theme.palette.warning.main, 0.12),
|
||||
},
|
||||
},
|
||||
outlinedError: {
|
||||
borderColor: theme.palette.error.main,
|
||||
color: getColor(theme.palette.error.main, 0.12),
|
||||
'& .MuiAlertTitle-root': {
|
||||
color: getColor(theme.palette.error.main, 0.12),
|
||||
},
|
||||
'& .MuiAlert-icon': {
|
||||
color: getColor(theme.palette.error.main, 0.12),
|
||||
},
|
||||
},
|
||||
filled: {
|
||||
fontWeight: 400,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Alert;
|
@@ -0,0 +1,27 @@
|
||||
const Avatar = theme => {
|
||||
return {
|
||||
MuiAvatar: {
|
||||
styleOverrides: {
|
||||
colorDefault: {
|
||||
color: theme.palette.text.secondary,
|
||||
backgroundColor: theme.palette.mode === 'light' ? theme.palette.grey[200] : theme.palette.grey[700],
|
||||
},
|
||||
rounded: {
|
||||
borderRadius: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAvatarGroup: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
justifyContent: 'flex-end',
|
||||
'.MuiCard-root & .MuiAvatar-root': {
|
||||
borderColor: theme.palette.background.paper,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Avatar;
|
@@ -0,0 +1,22 @@
|
||||
// ** Util Import
|
||||
import { hexToRGBA } from 'src/@core/utils/hex-to-rgba';
|
||||
|
||||
const Backdrop = theme => {
|
||||
return {
|
||||
MuiBackdrop: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor:
|
||||
theme.palette.mode === 'light'
|
||||
? `rgba(${theme.palette.customColors.main}, 0.7)`
|
||||
: hexToRGBA(theme.palette.background.default, 0.7),
|
||||
},
|
||||
invisible: {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Backdrop;
|
@@ -0,0 +1,50 @@
|
||||
// ** Theme Config Imports
|
||||
import themeConfig from 'src/configs/themeConfig';
|
||||
|
||||
const Button = theme => {
|
||||
return {
|
||||
MuiButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
fontWeight: 500,
|
||||
borderRadius: 5,
|
||||
lineHeight: 1.71,
|
||||
letterSpacing: '0.3px',
|
||||
padding: `${theme.spacing(1.875, 3)}`,
|
||||
},
|
||||
contained: {
|
||||
boxShadow: theme.shadows[3],
|
||||
padding: `${theme.spacing(1.875, 5.5)}`,
|
||||
},
|
||||
outlined: {
|
||||
padding: `${theme.spacing(1.625, 5.25)}`,
|
||||
},
|
||||
sizeSmall: {
|
||||
padding: `${theme.spacing(1, 2.25)}`,
|
||||
'&.MuiButton-contained': {
|
||||
padding: `${theme.spacing(1, 3.5)}`,
|
||||
},
|
||||
'&.MuiButton-outlined': {
|
||||
padding: `${theme.spacing(0.75, 3.25)}`,
|
||||
},
|
||||
},
|
||||
sizeLarge: {
|
||||
padding: `${theme.spacing(2.125, 5.5)}`,
|
||||
'&.MuiButton-contained': {
|
||||
padding: `${theme.spacing(2.125, 6.5)}`,
|
||||
},
|
||||
'&.MuiButton-outlined': {
|
||||
padding: `${theme.spacing(1.875, 6.25)}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiButtonBase: {
|
||||
defaultProps: {
|
||||
disableRipple: themeConfig.disableRipple,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Button;
|
@@ -0,0 +1,83 @@
|
||||
const Card = theme => {
|
||||
return {
|
||||
MuiCard: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
boxShadow: theme.shadows[6],
|
||||
'& .card-more-options': {
|
||||
marginTop: theme.spacing(-1),
|
||||
marginRight: theme.spacing(-3),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardHeader: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(5),
|
||||
'& + .MuiCardContent-root, & + .MuiCollapse-root .MuiCardContent-root': {
|
||||
paddingTop: 0,
|
||||
},
|
||||
'& .MuiCardHeader-subheader': {
|
||||
fontSize: '0.875rem',
|
||||
},
|
||||
},
|
||||
title: {
|
||||
lineHeight: 1,
|
||||
fontWeight: 500,
|
||||
fontSize: '1.25rem',
|
||||
letterSpacing: '0.0125em',
|
||||
},
|
||||
action: {
|
||||
marginTop: 0,
|
||||
marginRight: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(5),
|
||||
'& + .MuiCardContent-root': {
|
||||
paddingTop: 0,
|
||||
},
|
||||
'&:last-of-type': {
|
||||
paddingBottom: theme.spacing(5),
|
||||
},
|
||||
'& + .MuiCardActions-root': {
|
||||
paddingTop: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardActions: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(5),
|
||||
'&.card-action-dense': {
|
||||
padding: theme.spacing(0, 2.5, 2.5),
|
||||
'.MuiCard-root .MuiCardMedia-root + &': {
|
||||
paddingTop: theme.spacing(2.5),
|
||||
},
|
||||
'.MuiCard-root &:first-of-type': {
|
||||
paddingTop: theme.spacing(5),
|
||||
paddingBottom: theme.spacing(5),
|
||||
'& + .MuiCardContent-root': {
|
||||
paddingTop: 0,
|
||||
},
|
||||
'& + .MuiCardHeader-root': {
|
||||
paddingTop: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
'& .MuiButton-text': {
|
||||
paddingLeft: theme.spacing(2.5),
|
||||
paddingRight: theme.spacing(2.5),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Card;
|
@@ -0,0 +1,19 @@
|
||||
const Chip = theme => {
|
||||
return {
|
||||
MuiChip: {
|
||||
styleOverrides: {
|
||||
outlined: {
|
||||
'&.MuiChip-colorDefault': {
|
||||
borderColor: `rgba(${theme.palette.customColors.main}, 0.22)`,
|
||||
},
|
||||
},
|
||||
deleteIcon: {
|
||||
width: 18,
|
||||
height: 18,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Chip;
|
@@ -0,0 +1,61 @@
|
||||
const DateTimePicker = theme => {
|
||||
return {
|
||||
MuiCalendarPicker: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& [role="presentation"]': {
|
||||
fontWeight: 400,
|
||||
'& .PrivatePickersFadeTransitionGroup-root + .PrivatePickersFadeTransitionGroup-root > div': {
|
||||
marginRight: 0,
|
||||
},
|
||||
'& .MuiIconButton-sizeSmall': {
|
||||
padding: theme.spacing(0.5),
|
||||
},
|
||||
'& + div .MuiIconButton-root:not(.Mui-disabled)': {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
},
|
||||
'& .PrivatePickersSlideTransition-root': {
|
||||
minHeight: 240,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPickersDay: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
fontSize: '0.875rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiClockPicker: {
|
||||
styleOverrides: {
|
||||
arrowSwitcher: {
|
||||
'& .MuiIconButton-root:not(.Mui-disabled)': {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
'& + div': {
|
||||
'& > div': {
|
||||
backgroundColor:
|
||||
theme.palette.mode === 'light' ? theme.palette.grey[50] : theme.palette.background.default,
|
||||
'& ~ .MuiIconButton-root span.MuiTypography-caption': {
|
||||
color: 'inherit',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiMonthPicker: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& > .MuiTypography-root.Mui-selected': {
|
||||
fontSize: '1rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default DateTimePicker;
|
@@ -0,0 +1,104 @@
|
||||
// ** Util Import
|
||||
import { hexToRGBA } from 'src/@core/utils/hex-to-rgba';
|
||||
|
||||
const Dialog = theme => {
|
||||
return {
|
||||
MuiDialog: {
|
||||
styleOverrides: {
|
||||
paper: {
|
||||
boxShadow: theme.shadows[6],
|
||||
'&:not(.MuiDialog-paperFullScreen)': {
|
||||
'@media (max-width:599px)': {
|
||||
margin: theme.spacing(4),
|
||||
width: `calc(100% - ${theme.spacing(8)})`,
|
||||
maxWidth: `calc(100% - ${theme.spacing(8)}) !important`,
|
||||
},
|
||||
},
|
||||
'& > .MuiList-root': {
|
||||
paddingLeft: theme.spacing(1),
|
||||
paddingRight: theme.spacing(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDialogTitle: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(5),
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDialogContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(5),
|
||||
'& + .MuiDialogContent-root': {
|
||||
paddingTop: 0,
|
||||
},
|
||||
'& + .MuiDialogActions-root': {
|
||||
paddingTop: 0,
|
||||
},
|
||||
|
||||
// Styling for Mobile Date Picker starts
|
||||
'& .PrivatePickersToolbar-root': {
|
||||
padding: theme.spacing(4, 5),
|
||||
color: theme.palette.primary.contrastText,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
'& .MuiTypography-root': {
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
'& span.MuiTypography-overline': {
|
||||
fontSize: '1rem',
|
||||
lineHeight: '24px',
|
||||
letterSpacing: '0.15px',
|
||||
},
|
||||
'& ~ div[class^="css-"] > div[class^="css-"]': {
|
||||
marginTop: theme.spacing(6),
|
||||
marginBottom: theme.spacing(6),
|
||||
'& > div[class^="css-"]': {
|
||||
backgroundColor:
|
||||
theme.palette.mode === 'light' ? theme.palette.grey[50] : theme.palette.background.default,
|
||||
'& ~ .MuiIconButton-root span.MuiTypography-caption': {
|
||||
color: 'inherit',
|
||||
},
|
||||
},
|
||||
},
|
||||
'& .PrivateTimePickerToolbar-hourMinuteLabel': {
|
||||
alignItems: 'center',
|
||||
'& > .MuiButton-root span.MuiTypography-root': {
|
||||
fontWeight: 300,
|
||||
lineHeight: '72px',
|
||||
fontSize: '3.75rem',
|
||||
letterSpacing: '-0.5px',
|
||||
},
|
||||
'& > .MuiTypography-root': {
|
||||
color: hexToRGBA(theme.palette.primary.contrastText, 0.54),
|
||||
'& + .MuiButton-root > span.MuiTypography-root': {
|
||||
color: hexToRGBA(theme.palette.primary.contrastText, 0.54),
|
||||
},
|
||||
},
|
||||
},
|
||||
'& .PrivateTimePickerToolbar-ampmSelection span.MuiTypography-root:not(.Mui-selected)': {
|
||||
color: hexToRGBA(theme.palette.primary.contrastText, 0.54),
|
||||
},
|
||||
},
|
||||
|
||||
// Styling for Mobile Date Picker ends
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDialogActions: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: theme.spacing(5),
|
||||
'&.dialog-actions-dense': {
|
||||
padding: theme.spacing(2.5),
|
||||
paddingTop: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Dialog;
|
@@ -0,0 +1,13 @@
|
||||
const Divider = theme => {
|
||||
return {
|
||||
MuiDivider: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
margin: `${theme.spacing(2)} 0`,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Divider;
|
@@ -0,0 +1,85 @@
|
||||
// ** Overrides Imports
|
||||
import MuiCard from './card';
|
||||
import MuiChip from './chip';
|
||||
import MuiLink from './link';
|
||||
import MuiList from './list';
|
||||
import MuiMenu from './menu';
|
||||
import MuiTabs from './tabs';
|
||||
import MuiInput from './input';
|
||||
import MuiPaper from './paper';
|
||||
import MuiTable from './table';
|
||||
import MuiAlerts from './alerts';
|
||||
import MuiButton from './button';
|
||||
import MuiDialog from './dialog';
|
||||
import MuiRating from './rating';
|
||||
import MuiSelect from './select';
|
||||
import MuiAvatar from './avatars';
|
||||
import MuiDivider from './divider';
|
||||
import MuiPopover from './popover';
|
||||
import MuiTooltip from './tooltip';
|
||||
import MuiBackdrop from './backdrop';
|
||||
import MuiSnackbar from './snackbar';
|
||||
import MuiSwitches from './switches';
|
||||
import MuiTimeline from './timeline';
|
||||
import MuiAccordion from './accordion';
|
||||
import MuiPagination from './pagination';
|
||||
import MuiTypography from './typography';
|
||||
import MuiToggleButton from './toggleButton';
|
||||
import MuiDateTimePicker from './dateTimePicker';
|
||||
|
||||
const Overrides = theme => {
|
||||
const chip = MuiChip(theme);
|
||||
const list = MuiList(theme);
|
||||
const menu = MuiMenu(theme);
|
||||
const tabs = MuiTabs(theme);
|
||||
const cards = MuiCard(theme);
|
||||
const input = MuiInput(theme);
|
||||
const tables = MuiTable(theme);
|
||||
const alerts = MuiAlerts(theme);
|
||||
const button = MuiButton(theme);
|
||||
const rating = MuiRating(theme);
|
||||
const avatars = MuiAvatar(theme);
|
||||
const divider = MuiDivider(theme);
|
||||
const dialog = MuiDialog(theme);
|
||||
const popover = MuiPopover(theme);
|
||||
const tooltip = MuiTooltip(theme);
|
||||
const backdrop = MuiBackdrop(theme);
|
||||
const snackbar = MuiSnackbar(theme);
|
||||
const switches = MuiSwitches(theme);
|
||||
const timeline = MuiTimeline(theme);
|
||||
const accordion = MuiAccordion(theme);
|
||||
const pagination = MuiPagination(theme);
|
||||
const dateTimePicker = MuiDateTimePicker(theme);
|
||||
|
||||
return Object.assign(
|
||||
chip,
|
||||
list,
|
||||
menu,
|
||||
tabs,
|
||||
cards,
|
||||
input,
|
||||
alerts,
|
||||
button,
|
||||
dialog,
|
||||
rating,
|
||||
tables,
|
||||
avatars,
|
||||
divider,
|
||||
MuiLink,
|
||||
popover,
|
||||
tooltip,
|
||||
backdrop,
|
||||
MuiPaper,
|
||||
snackbar,
|
||||
switches,
|
||||
timeline,
|
||||
accordion,
|
||||
MuiSelect,
|
||||
pagination,
|
||||
MuiTypography,
|
||||
dateTimePicker,
|
||||
MuiToggleButton,
|
||||
);
|
||||
};
|
||||
|
||||
export default Overrides;
|
@@ -0,0 +1,62 @@
|
||||
const input = theme => {
|
||||
return {
|
||||
MuiInputLabel: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiInput: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&:before': {
|
||||
borderBottom: `1px solid rgba(${theme.palette.customColors.main}, 0.22)`,
|
||||
},
|
||||
'&:hover:not(.Mui-disabled):before': {
|
||||
borderBottom: `1px solid rgba(${theme.palette.customColors.main}, 0.32)`,
|
||||
},
|
||||
'&.Mui-disabled:before': {
|
||||
borderBottom: `1px solid ${theme.palette.text.disabled}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiFilledInput: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: `rgba(${theme.palette.customColors.main}, 0.04)`,
|
||||
'&:hover:not(.Mui-disabled)': {
|
||||
backgroundColor: `rgba(${theme.palette.customColors.main}, 0.08)`,
|
||||
},
|
||||
'&:before': {
|
||||
borderBottom: `1px solid rgba(${theme.palette.customColors.main}, 0.22)`,
|
||||
},
|
||||
'&:hover:not(.Mui-disabled):before': {
|
||||
borderBottom: `1px solid rgba(${theme.palette.customColors.main}, 0.32)`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiOutlinedInput: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&:hover:not(.Mui-focused) .MuiOutlinedInput-notchedOutline': {
|
||||
borderColor: `rgba(${theme.palette.customColors.main}, 0.32)`,
|
||||
},
|
||||
'&:hover.Mui-error .MuiOutlinedInput-notchedOutline': {
|
||||
borderColor: theme.palette.error.main,
|
||||
},
|
||||
'& .MuiOutlinedInput-notchedOutline': {
|
||||
borderColor: `rgba(${theme.palette.customColors.main}, 0.22)`,
|
||||
},
|
||||
'&.Mui-disabled .MuiOutlinedInput-notchedOutline': {
|
||||
borderColor: theme.palette.text.disabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default input;
|
@@ -0,0 +1,9 @@
|
||||
export default {
|
||||
MuiLink: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
textDecoration: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
@@ -0,0 +1,41 @@
|
||||
const List = theme => {
|
||||
return {
|
||||
MuiListItemIcon: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
minWidth: 0,
|
||||
marginRight: theme.spacing(2.25),
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiListItemAvatar: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
minWidth: 0,
|
||||
marginRight: theme.spacing(4),
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiListItemText: {
|
||||
styleOverrides: {
|
||||
dense: {
|
||||
'& .MuiListItemText-primary': {
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiListSubheader: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
fontWeight: 600,
|
||||
textTransform: 'uppercase',
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default List;
|
@@ -0,0 +1,16 @@
|
||||
const Menu = theme => {
|
||||
return {
|
||||
MuiMenu: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiMenu-paper': {
|
||||
borderRadius: 5,
|
||||
boxShadow: theme.palette.mode === 'light' ? theme.shadows[8] : theme.shadows[9],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Menu;
|
@@ -0,0 +1,38 @@
|
||||
// ** Util Import
|
||||
import { hexToRGBA } from 'src/@core/utils/hex-to-rgba';
|
||||
|
||||
const Pagination = theme => {
|
||||
return {
|
||||
MuiPaginationItem: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.Mui-selected:not(.Mui-disabled):not(.MuiPaginationItem-textPrimary):not(.MuiPaginationItem-textSecondary):hover':
|
||||
{
|
||||
backgroundColor: `rgba(${theme.palette.customColors.main}, 0.12)`,
|
||||
},
|
||||
},
|
||||
outlined: {
|
||||
borderColor: `rgba(${theme.palette.customColors.main}, 0.22)`,
|
||||
},
|
||||
outlinedPrimary: {
|
||||
'&.Mui-selected': {
|
||||
backgroundColor: hexToRGBA(theme.palette.primary.main, 0.12),
|
||||
'&:hover': {
|
||||
backgroundColor: `${hexToRGBA(theme.palette.primary.main, 0.2)} !important`,
|
||||
},
|
||||
},
|
||||
},
|
||||
outlinedSecondary: {
|
||||
'&.Mui-selected': {
|
||||
backgroundColor: hexToRGBA(theme.palette.secondary.main, 0.12),
|
||||
'&:hover': {
|
||||
backgroundColor: `${hexToRGBA(theme.palette.secondary.main, 0.2)} !important`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Pagination;
|
@@ -0,0 +1,9 @@
|
||||
export default {
|
||||
MuiPaper: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundImage: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
@@ -0,0 +1,15 @@
|
||||
const Popover = theme => {
|
||||
return {
|
||||
MuiPopover: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiPopover-paper': {
|
||||
boxShadow: theme.shadows[6],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Popover;
|
@@ -0,0 +1,13 @@
|
||||
const Rating = theme => {
|
||||
return {
|
||||
MuiRating: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: theme.palette.warning.main,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Rating;
|
@@ -0,0 +1,12 @@
|
||||
export default {
|
||||
MuiSelect: {
|
||||
styleOverrides: {
|
||||
select: {
|
||||
minWidth: '6rem !important',
|
||||
'&.MuiTablePagination-select': {
|
||||
minWidth: '1rem !important',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
@@ -0,0 +1,13 @@
|
||||
const Snackbar = theme => {
|
||||
return {
|
||||
MuiSnackbarContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: theme.palette.mode === 'light' ? theme.palette.grey[900] : theme.palette.grey[100],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Snackbar;
|
@@ -0,0 +1,15 @@
|
||||
const Switch = theme => {
|
||||
return {
|
||||
MuiSwitch: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiSwitch-track': {
|
||||
backgroundColor: `rgb(${theme.palette.customColors.main})`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Switch;
|
@@ -0,0 +1,66 @@
|
||||
const Table = theme => {
|
||||
return {
|
||||
MuiTableContainer: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
boxShadow: theme.shadows[0],
|
||||
borderTopColor: theme.palette.divider,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableHead: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
textTransform: 'uppercase',
|
||||
'& .MuiTableCell-head': {
|
||||
fontSize: '0.75rem',
|
||||
fontWeight: 600,
|
||||
letterSpacing: '0.13px',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableBody: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiTableCell-body': {
|
||||
letterSpacing: '0.25px',
|
||||
color: theme.palette.text.secondary,
|
||||
'&:not(.MuiTableCell-sizeSmall):not(.MuiTableCell-paddingCheckbox):not(.MuiTableCell-paddingNone)': {
|
||||
paddingTop: theme.spacing(3.5),
|
||||
paddingBottom: theme.spacing(3.5),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableRow: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiTableCell-head:first-child, & .MuiTableCell-root:first-child ': {
|
||||
paddingLeft: theme.spacing(5),
|
||||
},
|
||||
'& .MuiTableCell-head:last-child, & .MuiTableCell-root:last-child': {
|
||||
paddingRight: theme.spacing(5),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableCell: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
'& .MuiButton-root': {
|
||||
textTransform: 'uppercase',
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
},
|
||||
stickyHeader: {
|
||||
backgroundColor: theme.palette.customColors.tableHeaderBg,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Table;
|
@@ -0,0 +1,27 @@
|
||||
const Tabs = theme => {
|
||||
return {
|
||||
MuiTabs: {
|
||||
styleOverrides: {
|
||||
vertical: {
|
||||
minWidth: 130,
|
||||
marginRight: theme.spacing(4),
|
||||
borderRight: `1px solid ${theme.palette.divider}`,
|
||||
'& .MuiTab-root': {
|
||||
minWidth: 130,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTab: {
|
||||
styleOverrides: {
|
||||
textColorSecondary: {
|
||||
'&.Mui-selected': {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Tabs;
|
@@ -0,0 +1,80 @@
|
||||
// ** Util Import
|
||||
import { hexToRGBA } from 'src/@core/utils/hex-to-rgba';
|
||||
|
||||
const Timeline = theme => {
|
||||
return {
|
||||
MuiTimelineItem: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&:not(:last-of-type)': {
|
||||
'& .MuiTimelineContent-root': {
|
||||
marginBottom: theme.spacing(4),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTimelineConnector: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: theme.palette.divider,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTimelineContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
marginTop: theme.spacing(0.5),
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTimelineDot: {
|
||||
styleOverrides: {
|
||||
filledPrimary: {
|
||||
boxShadow: `0 0 0 3px ${hexToRGBA(theme.palette.primary.main, 0.12)}`,
|
||||
},
|
||||
filledSecondary: {
|
||||
boxShadow: `0 0 0 3px ${hexToRGBA(theme.palette.secondary.main, 0.12)}`,
|
||||
},
|
||||
filledSuccess: {
|
||||
boxShadow: `0 0 0 3px ${hexToRGBA(theme.palette.success.main, 0.12)}`,
|
||||
},
|
||||
filledError: {
|
||||
boxShadow: `0 0 0 3px ${hexToRGBA(theme.palette.error.main, 0.12)}`,
|
||||
},
|
||||
filledWarning: {
|
||||
boxShadow: `0 0 0 3px ${hexToRGBA(theme.palette.warning.main, 0.12)}`,
|
||||
},
|
||||
filledInfo: {
|
||||
boxShadow: `0 0 0 3px ${hexToRGBA(theme.palette.info.main, 0.12)}`,
|
||||
},
|
||||
filledGrey: {
|
||||
boxShadow: `0 0 0 3px ${hexToRGBA(theme.palette.grey[400], 0.12)}`,
|
||||
},
|
||||
outlinedPrimary: {
|
||||
'& svg': { color: theme.palette.primary.main },
|
||||
},
|
||||
outlinedSecondary: {
|
||||
'& svg': { color: theme.palette.secondary.main },
|
||||
},
|
||||
outlinedSuccess: {
|
||||
'& svg': { color: theme.palette.success.main },
|
||||
},
|
||||
outlinedError: {
|
||||
'& svg': { color: theme.palette.error.main },
|
||||
},
|
||||
outlinedWarning: {
|
||||
'& svg': { color: theme.palette.warning.main },
|
||||
},
|
||||
outlinedInfo: {
|
||||
'& svg': { color: theme.palette.info.main },
|
||||
},
|
||||
outlinedGrey: {
|
||||
'& svg': { color: theme.palette.grey[500] },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Timeline;
|
@@ -0,0 +1,16 @@
|
||||
export default {
|
||||
MuiToggleButtonGroup: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 4,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiToggleButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 4,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
@@ -0,0 +1,25 @@
|
||||
// ** Util Import
|
||||
import { hexToRGBA } from 'src/@core/utils/hex-to-rgba';
|
||||
|
||||
const Tooltip = theme => {
|
||||
return {
|
||||
MuiTooltip: {
|
||||
styleOverrides: {
|
||||
tooltip: {
|
||||
backgroundColor:
|
||||
theme.palette.mode === 'light'
|
||||
? hexToRGBA(theme.palette.grey[900], 0.9)
|
||||
: hexToRGBA(theme.palette.grey[700], 0.9),
|
||||
},
|
||||
arrow: {
|
||||
color:
|
||||
theme.palette.mode === 'light'
|
||||
? hexToRGBA(theme.palette.grey[900], 0.9)
|
||||
: hexToRGBA(theme.palette.grey[700], 0.9),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Tooltip;
|
@@ -0,0 +1,13 @@
|
||||
const Typography = theme => {
|
||||
return {
|
||||
MuiTypography: {
|
||||
styleOverrides: {
|
||||
gutterBottom: {
|
||||
marginBottom: theme.spacing(2),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Typography;
|
@@ -0,0 +1,107 @@
|
||||
const DefaultPalette = (mode, themeColor) => {
|
||||
// ** Vars
|
||||
const lightColor = '58, 53, 65';
|
||||
const darkColor = '231, 227, 252';
|
||||
const mainColor = mode === 'light' ? lightColor : darkColor;
|
||||
|
||||
const primaryGradient = () => {
|
||||
if (themeColor === 'primary') {
|
||||
return 'rgba(12, 45, 87,0.7)';
|
||||
} else if (themeColor === 'secondary') {
|
||||
return '#9C9FA4';
|
||||
} else if (themeColor === 'success') {
|
||||
return '#93DD5C';
|
||||
} else if (themeColor === 'error') {
|
||||
return '#FF8C90';
|
||||
} else if (themeColor === 'warning') {
|
||||
return '#FFCF5C';
|
||||
} else {
|
||||
return '#6ACDFF';
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
customColors: {
|
||||
main: mainColor,
|
||||
primaryGradient: primaryGradient(),
|
||||
tableHeaderBg: mode === 'light' ? '#F9FAFC' : '#3D3759',
|
||||
},
|
||||
common: {
|
||||
black: '#000',
|
||||
white: '#FFF',
|
||||
},
|
||||
mode: mode,
|
||||
primary: {
|
||||
light: 'rgba(12, 45, 87,0.2)',
|
||||
main: 'rgba(12, 45, 87,0.7)',
|
||||
dark: 'rgba(12, 45, 87,1)',
|
||||
contrastText: '#FFF',
|
||||
},
|
||||
secondary: {
|
||||
light: '#9C9FA4',
|
||||
main: '#8A8D93',
|
||||
dark: '#777B82',
|
||||
contrastText: '#FFF',
|
||||
},
|
||||
success: {
|
||||
light: '#6AD01F',
|
||||
main: '#56CA00',
|
||||
dark: '#4CB200',
|
||||
contrastText: '#FFF',
|
||||
},
|
||||
error: {
|
||||
light: '#FF6166',
|
||||
main: '#FF4C51',
|
||||
dark: '#E04347',
|
||||
contrastText: '#FFF',
|
||||
},
|
||||
warning: {
|
||||
light: '#FFCA64',
|
||||
main: '#FFB400',
|
||||
dark: '#E09E00',
|
||||
contrastText: '#FFF',
|
||||
},
|
||||
info: {
|
||||
light: '#32BAFF',
|
||||
main: '#16B1FF',
|
||||
dark: '#139CE0',
|
||||
contrastText: '#FFF',
|
||||
},
|
||||
grey: {
|
||||
50: '#FAFAFA',
|
||||
100: '#F5F5F5',
|
||||
200: '#EEEEEE',
|
||||
300: '#E0E0E0',
|
||||
400: '#BDBDBD',
|
||||
500: '#9E9E9E',
|
||||
600: '#757575',
|
||||
700: '#616161',
|
||||
800: '#424242',
|
||||
900: '#212121',
|
||||
A100: '#D5D5D5',
|
||||
A200: '#AAAAAA',
|
||||
A400: '#616161',
|
||||
A700: '#303030',
|
||||
},
|
||||
text: {
|
||||
primary: `rgba(${mainColor}, 0.87)`,
|
||||
secondary: `rgba(${mainColor}, 0.68)`,
|
||||
disabled: `rgba(${mainColor}, 0.38)`,
|
||||
},
|
||||
divider: `rgba(${mainColor}, 0.12)`,
|
||||
background: {
|
||||
paper: mode === 'light' ? '#FFF' : '#312D4B',
|
||||
default: mode === 'light' ? '#F4F5FA' : '#28243D',
|
||||
},
|
||||
action: {
|
||||
active: `rgba(${mainColor}, 0.54)`,
|
||||
hover: `rgba(${mainColor}, 0.04)`,
|
||||
selected: `rgba(${mainColor}, 0.08)`,
|
||||
disabled: `rgba(${mainColor}, 0.3)`,
|
||||
disabledBackground: `rgba(${mainColor}, 0.18)`,
|
||||
focus: `rgba(${mainColor}, 0.12)`,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default DefaultPalette;
|
@@ -0,0 +1,61 @@
|
||||
const Shadows = mode => {
|
||||
if (mode === 'light') {
|
||||
return [
|
||||
'none',
|
||||
'0px 2px 1px -1px rgba(58, 53, 65, 0.2), 0px 1px 1px 0px rgba(58, 53, 65, 0.14), 0px 1px 3px 0px rgba(58, 53, 65, 0.12)',
|
||||
'0px 3px 1px -2px rgba(58, 53, 65, 0.2), 0px 2px 2px 0px rgba(58, 53, 65, 0.14), 0px 1px 5px 0px rgba(58, 53, 65, 0.12)',
|
||||
'0px 4px 8px -4px rgba(58, 53, 65, 0.42)',
|
||||
'0px 6px 18px -8px rgba(58, 53, 65, 0.56)',
|
||||
'0px 3px 5px -1px rgba(58, 53, 65, 0.2), 0px 5px 8px 0px rgba(58, 53, 65, 0.14), 0px 1px 14px 0px rgba(58, 53, 65, 0.12)',
|
||||
'0px 2px 10px 0px rgba(58, 53, 65, 0.1)',
|
||||
'0px 4px 5px -2px rgba(58, 53, 65, 0.2), 0px 7px 10px 1px rgba(58, 53, 65, 0.14), 0px 2px 16px 1px rgba(58, 53, 65, 0.12)',
|
||||
'0px 5px 5px -3px rgba(58, 53, 65, 0.2), 0px 8px 10px 1px rgba(58, 53, 65, 0.14), 0px 3px 14px 2px rgba(58, 53, 65, 0.12)',
|
||||
'0px 5px 6px -3px rgba(58, 53, 65, 0.2), 0px 9px 12px 1px rgba(58, 53, 65, 0.14), 0px 3px 16px 2px rgba(58, 53, 65, 0.12)',
|
||||
'0px 6px 6px -3px rgba(58, 53, 65, 0.2), 0px 10px 14px 1px rgba(58, 53, 65, 0.14), 0px 4px 18px 3px rgba(58, 53, 65, 0.12)',
|
||||
'0px 6px 7px -4px rgba(58, 53, 65, 0.2), 0px 11px 15px 1px rgba(58, 53, 65, 0.14), 0px 4px 20px 3px rgba(58, 53, 65, 0.12)',
|
||||
'0px 7px 8px -4px rgba(58, 53, 65, 0.2), 0px 12px 17px 2px rgba(58, 53, 65, 0.14), 0px 5px 22px 4px rgba(58, 53, 65, 0.12)',
|
||||
'0px 7px 8px -4px rgba(58, 53, 65, 0.2), 0px 13px 19px 2px rgba(58, 53, 65, 0.14), 0px 5px 24px 4px rgba(58, 53, 65, 0.12)',
|
||||
'0px 7px 9px -4px rgba(58, 53, 65, 0.2), 0px 14px 21px 2px rgba(58, 53, 65, 0.14), 0px 5px 26px 4px rgba(58, 53, 65, 0.12)',
|
||||
'0px 8px 9px -5px rgba(58, 53, 65, 0.2), 0px 15px 22px 2px rgba(58, 53, 65, 0.14), 0px 6px 28px 5px rgba(58, 53, 65, 0.12)',
|
||||
'0px 8px 10px -5px rgba(58, 53, 65, 0.2), 0px 16px 24px 2px rgba(58, 53, 65, 0.14), 0px 6px 30px 5px rgba(58, 53, 65, 0.12)',
|
||||
'0px 8px 11px -5px rgba(58, 53, 65, 0.2), 0px 17px 26px 2px rgba(58, 53, 65, 0.14), 0px 6px 32px 5px rgba(58, 53, 65, 0.12)',
|
||||
'0px 9px 11px -5px rgba(58, 53, 65, 0.2), 0px 18px 28px 2px rgba(58, 53, 65, 0.14), 0px 7px 34px 6px rgba(58, 53, 65, 0.12)',
|
||||
'0px 9px 12px -6px rgba(58, 53, 65, 0.2), 0px 19px 29px 2px rgba(58, 53, 65, 0.14), 0px 7px 36px 6px rgba(58, 53, 65, 0.12)',
|
||||
'0px 10px 13px -6px rgba(58, 53, 65, 0.2), 0px 20px 31px 3px rgba(58, 53, 65, 0.14), 0px 8px 38px 7px rgba(58, 53, 65, 0.12)',
|
||||
'0px 10px 13px -6px rgba(58, 53, 65, 0.2), 0px 21px 33px 3px rgba(58, 53, 65, 0.14), 0px 8px 40px 7px rgba(58, 53, 65, 0.12)',
|
||||
'0px 10px 14px -6px rgba(58, 53, 65, 0.2), 0px 22px 35px 3px rgba(58, 53, 65, 0.14), 0px 8px 42px 7px rgba(58, 53, 65, 0.12)',
|
||||
'0px 11px 14px -7px rgba(58, 53, 65, 0.2), 0px 23px 36px 3px rgba(58, 53, 65, 0.14), 0px 9px 44px 8px rgba(58, 53, 65, 0.12)',
|
||||
'0px 11px 15px -7px rgba(58, 53, 65, 0.2), 0px 24px 38px 3px rgba(58, 53, 65, 0.14), 0px 9px 46px 8px rgba(58, 53, 65, 0.12)',
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'none',
|
||||
'0px 2px 1px -1px rgba(19, 17, 32, 0.2), 0px 1px 1px 0px rgba(19, 17, 32, 0.14), 0px 1px 3px 0px rgba(19, 17, 32, 0.12)',
|
||||
'0px 3px 1px -2px rgba(19, 17, 32, 0.2), 0px 2px 2px 0px rgba(19, 17, 32, 0.14), 0px 1px 5px 0px rgba(19, 17, 32, 0.12)',
|
||||
'0px 4px 8px -4px rgba(19, 17, 32, 0.42)',
|
||||
'0px 6px 18px -8px rgba(19, 17, 32, 0.56)',
|
||||
'0px 3px 5px -1px rgba(19, 17, 32, 0.2), 0px 5px 8px rgba(19, 17, 32, 0.14), 0px 1px 14px rgba(19, 17, 32, 0.12)',
|
||||
'0px 2px 10px 0px rgba(19, 17, 32, 0.1)',
|
||||
'0px 4px 5px -2px rgba(19, 17, 32, 0.2), 0px 7px 10px 1px rgba(19, 17, 32, 0.14), 0px 2px 16px 1px rgba(19, 17, 32, 0.12)',
|
||||
'0px 5px 5px -3px rgba(19, 17, 32, 0.2), 0px 8px 10px 1px rgba(19, 17, 32, 0.14), 0px 3px 14px 2px rgba(19, 17, 32, 0.12)',
|
||||
'0px 5px 6px -3px rgba(19, 17, 32, 0.2), 0px 9px 12px 1px rgba(19, 17, 32, 0.14), 0px 3px 16px 2px rgba(19, 17, 32, 0.12)',
|
||||
'0px 6px 6px -3px rgba(19, 17, 32, 0.2), 0px 10px 14px 1px rgba(19, 17, 32, 0.14), 0px 4px 18px 3px rgba(19, 17, 32, 0.12)',
|
||||
'0px 6px 7px -4px rgba(19, 17, 32, 0.2), 0px 11px 15px 1px rgba(19, 17, 32, 0.14), 0px 4px 20px 3px rgba(19, 17, 32, 0.12)',
|
||||
'0px 7px 8px -4px rgba(19, 17, 32, 0.2), 0px 12px 17px 2px rgba(19, 17, 32, 0.14), 0px 5px 22px 4px rgba(19, 17, 32, 0.12)',
|
||||
'0px 7px 8px -4px rgba(19, 17, 32, 0.2), 0px 13px 19px 2px rgba(19, 17, 32, 0.14), 0px 5px 24px 4px rgba(19, 17, 32, 0.12)',
|
||||
'0px 7px 9px -4px rgba(19, 17, 32, 0.2), 0px 14px 21px 2px rgba(19, 17, 32, 0.14), 0px 5px 26px 4px rgba(19, 17, 32, 0.12)',
|
||||
'0px 8px 9px -5px rgba(19, 17, 32, 0.2), 0px 15px 22px 2px rgba(19, 17, 32, 0.14), 0px 6px 28px 5px rgba(19, 17, 32, 0.12)',
|
||||
'0px 8px 10px -5px rgba(19, 17, 32, 0.2), 0px 16px 24px 2px rgba(19, 17, 32, 0.14), 0px 6px 30px 5px rgba(19, 17, 32, 0.12)',
|
||||
'0px 8px 11px -5px rgba(19, 17, 32, 0.2), 0px 17px 26px 2px rgba(19, 17, 32, 0.14), 0px 6px 32px 5px rgba(19, 17, 32, 0.12)',
|
||||
'0px 9px 11px -5px rgba(19, 17, 32, 0.2), 0px 18px 28px 2px rgba(19, 17, 32, 0.14), 0px 7px 34px 6px rgba(19, 17, 32, 0.12)',
|
||||
'0px 9px 12px -6px rgba(19, 17, 32, 0.2), 0px 19px 29px 2px rgba(19, 17, 32, 0.14), 0px 7px 36px 6px rgba(19, 17, 32, 0.12)',
|
||||
'0px 10px 13px -6px rgba(19, 17, 32, 0.2), 0px 20px 31px 3px rgba(19, 17, 32, 0.14), 0px 8px 38px 7px rgba(19, 17, 32, 0.12)',
|
||||
'0px 10px 13px -6px rgba(19, 17, 32, 0.2), 0px 21px 33px 3px rgba(19, 17, 32, 0.14), 0px 8px 40px 7px rgba(19, 17, 32, 0.12)',
|
||||
'0px 10px 14px -6px rgba(19, 17, 32, 0.2), 0px 22px 35px 3px rgba(19, 17, 32, 0.14), 0px 8px 42px 7px rgba(19, 17, 32, 0.12)',
|
||||
'0px 11px 14px -7px rgba(19, 17, 32, 0.2), 0px 23px 36px 3px rgba(19, 17, 32, 0.14), 0px 9px 44px 8px rgba(19, 17, 32, 0.12)',
|
||||
'0px 11px 15px -7px rgba(19, 17, 32, 0.2), 0px 24px 38px 3px rgba(19, 17, 32, 0.14), 0px 9px 46px 8px rgba(19, 17, 32, 0.12)',
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
export default Shadows;
|
@@ -0,0 +1,3 @@
|
||||
export default {
|
||||
spacing: factor => `${0.25 * factor}rem`,
|
||||
};
|
@@ -0,0 +1,3 @@
|
||||
export default {
|
||||
spacing: factor => `${0.25 * factor}rem`
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
const Typography = theme => {
|
||||
return {
|
||||
h1: {
|
||||
fontWeight: 500,
|
||||
letterSpacing: '-1.5px',
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
h2: {
|
||||
fontWeight: 500,
|
||||
letterSpacing: '-0.5px',
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
h3: {
|
||||
fontWeight: 500,
|
||||
letterSpacing: 0,
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
h4: {
|
||||
fontWeight: 500,
|
||||
letterSpacing: '0.25px',
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
h5: {
|
||||
fontWeight: 500,
|
||||
letterSpacing: 0,
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
h6: {
|
||||
letterSpacing: '0.15px',
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
subtitle1: {
|
||||
letterSpacing: '0.15px',
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
subtitle2: {
|
||||
letterSpacing: '0.1px',
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
body1: {
|
||||
letterSpacing: '0.15px',
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
body2: {
|
||||
lineHeight: 1.5,
|
||||
letterSpacing: '0.15px',
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
button: {
|
||||
letterSpacing: '0.3px',
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
caption: {
|
||||
letterSpacing: '0.4px',
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
overline: {
|
||||
letterSpacing: '1px',
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Typography;
|
@@ -0,0 +1,5 @@
|
||||
import createCache from '@emotion/cache';
|
||||
|
||||
export const createEmotionCache = () => {
|
||||
return createCache({ key: 'css' });
|
||||
};
|
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
** Hex color to RGBA color
|
||||
*/
|
||||
export const hexToRGBA = (hexCode, opacity) => {
|
||||
let hex = hexCode.replace('#', '');
|
||||
if (hex.length === 3) {
|
||||
hex = `${hex[0]}${hex[0]}${hex[1]}${hex[1]}${hex[2]}${hex[2]}`;
|
||||
}
|
||||
const r = parseInt(hex.substring(0, 2), 16);
|
||||
const g = parseInt(hex.substring(2, 4), 16);
|
||||
const b = parseInt(hex.substring(4, 6), 16);
|
||||
|
||||
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
||||
};
|
15
tsc1877/task1/aws/workspace/admin/src/api/cancelOrder.js
Normal file
15
tsc1877/task1/aws/workspace/admin/src/api/cancelOrder.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import axios from 'axios';
|
||||
import { API_PREF } from './common';
|
||||
|
||||
const CancelOrder = ({ custom_id }) => {
|
||||
return axios
|
||||
.post(`/api/order/cancel-order`, { custom_id })
|
||||
.then(response => {
|
||||
return response['data']['state'];
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
export default CancelOrder;
|
10
tsc1877/task1/aws/workspace/admin/src/api/checkSession.js
Normal file
10
tsc1877/task1/aws/workspace/admin/src/api/checkSession.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const CheckSession = ({ session }) => {
|
||||
return axios
|
||||
.get(`/api/auth/check_session`, { headers: { session } })
|
||||
.then(res => res['data'])
|
||||
.catch(err => console.error(err));
|
||||
};
|
||||
|
||||
export default CheckSession;
|
15
tsc1877/task1/aws/workspace/admin/src/api/checkoutCart.js
Normal file
15
tsc1877/task1/aws/workspace/admin/src/api/checkoutCart.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import axios from 'axios';
|
||||
import { API_PREF } from './common';
|
||||
|
||||
const checkoutCart = items_to_checkout => {
|
||||
return axios
|
||||
.post(`/api/inventory/check_out`, items_to_checkout)
|
||||
.then(response => {
|
||||
return response;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
export default checkoutCart;
|
3
tsc1877/task1/aws/workspace/admin/src/api/common.js
Normal file
3
tsc1877/task1/aws/workspace/admin/src/api/common.js
Normal file
@@ -0,0 +1,3 @@
|
||||
const API_PREF = process.env.NEXT_PUBLIC_API_PREF;
|
||||
|
||||
export { API_PREF };
|
22
tsc1877/task1/aws/workspace/admin/src/api/fetchAllOrders.js
Normal file
22
tsc1877/task1/aws/workspace/admin/src/api/fetchAllOrders.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import axios from 'axios';
|
||||
import { API_PREF } from './common';
|
||||
|
||||
const fetchAllOrders = ({ session }) => {
|
||||
console.log({ session });
|
||||
|
||||
return axios
|
||||
.get(`/api/order/list`, { headers: { session } })
|
||||
.then(function (response) {
|
||||
let { data } = response;
|
||||
|
||||
let { orders } = data;
|
||||
|
||||
return orders;
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
export default fetchAllOrders;
|
21
tsc1877/task1/aws/workspace/admin/src/api/fetchCategories.js
Normal file
21
tsc1877/task1/aws/workspace/admin/src/api/fetchCategories.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import axios from 'axios';
|
||||
import { API_PREF } from './common';
|
||||
|
||||
const fetchCategories = () => {
|
||||
return axios
|
||||
.get(`/api/categories/list`)
|
||||
.then(function (response) {
|
||||
let { data } = response;
|
||||
let { categories } = data;
|
||||
return categories;
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error);
|
||||
})
|
||||
.finally(function () {
|
||||
// always executed
|
||||
});
|
||||
};
|
||||
|
||||
export default fetchCategories;
|
10
tsc1877/task1/aws/workspace/admin/src/api/fetchCategory.js
Normal file
10
tsc1877/task1/aws/workspace/admin/src/api/fetchCategory.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const fetchCategory = async ({ cid }) => {
|
||||
return axios
|
||||
.get(`/api/categories/view?cid=${cid}`)
|
||||
.then(res => res)
|
||||
.catch(err => console.error(err));
|
||||
};
|
||||
|
||||
export default fetchCategory;
|
@@ -0,0 +1,18 @@
|
||||
import axios from 'axios';
|
||||
import { API_PREF } from './common';
|
||||
|
||||
const fetchCustomerOrders = ({ session }) => {
|
||||
return axios
|
||||
.get(`/api/order/listByCustomer`, { headers: { session } })
|
||||
.then(function (response) {
|
||||
let { data } = response;
|
||||
let { orders } = data;
|
||||
return orders;
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
export default fetchCustomerOrders;
|
@@ -0,0 +1,10 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const fetchListByCategory = ({ cid }) => {
|
||||
return axios
|
||||
.get(`/api/products/listByCategory?cid=${cid}`)
|
||||
.then(res => res)
|
||||
.catch(err => console.error(err));
|
||||
};
|
||||
|
||||
export default fetchListByCategory;
|
@@ -0,0 +1,16 @@
|
||||
import axios from 'axios';
|
||||
import { API_PREF } from './common';
|
||||
|
||||
const fetchListByCategoryUnsold = ({ cid }) => {
|
||||
return axios
|
||||
.get(`/api/products/listByCategoryUnsold?cid=${cid}`)
|
||||
.then(res => {
|
||||
let {
|
||||
data: { products },
|
||||
} = res;
|
||||
return products;
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
};
|
||||
|
||||
export default fetchListByCategoryUnsold;
|
13
tsc1877/task1/aws/workspace/admin/src/api/fetchProduct.js
Normal file
13
tsc1877/task1/aws/workspace/admin/src/api/fetchProduct.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import axios from 'axios';
|
||||
import { API_PREF } from './common';
|
||||
|
||||
const fetchProduct = ({ pid }) => {
|
||||
return axios
|
||||
.get(`/api/products/view?pid=${pid}`)
|
||||
.then(res => {
|
||||
return res;
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
};
|
||||
|
||||
export default fetchProduct;
|
19
tsc1877/task1/aws/workspace/admin/src/api/fetchProducts.js
Normal file
19
tsc1877/task1/aws/workspace/admin/src/api/fetchProducts.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import axios from 'axios';
|
||||
import { API_PREF } from './common';
|
||||
|
||||
const fetchProducts = () => {
|
||||
return axios
|
||||
.get(`/api/products/list`)
|
||||
.then(function (response) {
|
||||
let { data } = response;
|
||||
let { products } = data;
|
||||
|
||||
return products;
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
export default fetchProducts;
|
18
tsc1877/task1/aws/workspace/admin/src/api/getOrderDetails.js
Normal file
18
tsc1877/task1/aws/workspace/admin/src/api/getOrderDetails.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import axios from 'axios';
|
||||
import { API_PREF } from './common';
|
||||
|
||||
const GetOrderDetails = ({ cart, currency_code }) => {
|
||||
let session_raw = localStorage.getItem('session');
|
||||
let { session } = JSON.parse(session_raw);
|
||||
|
||||
return axios
|
||||
.post(`/api/order/get-order-details`, { cart, currency_code }, { headers: { session } })
|
||||
.then(response => {
|
||||
return response['data'];
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
export default GetOrderDetails;
|
16
tsc1877/task1/aws/workspace/admin/src/api/saveOrder.js
Normal file
16
tsc1877/task1/aws/workspace/admin/src/api/saveOrder.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import axios from 'axios';
|
||||
import { API_PREF } from './common';
|
||||
import { csrf } from 'src/lib/csrf';
|
||||
|
||||
const SaveOrder = ({ custom_id }) => {
|
||||
return axios
|
||||
.post(`/api/order/save-order`, { custom_id })
|
||||
.then(response => {
|
||||
return response['data']['state'];
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
export default SaveOrder;
|
124
tsc1877/task1/aws/workspace/admin/src/components/CardProduct.js
Normal file
124
tsc1877/task1/aws/workspace/admin/src/components/CardProduct.js
Normal file
@@ -0,0 +1,124 @@
|
||||
// ** React Imports
|
||||
import { useContext } from 'react';
|
||||
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box';
|
||||
import Card from '@mui/material/Card';
|
||||
import Button from '@mui/material/Button';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import CardActions from '@mui/material/CardActions';
|
||||
import Grid from '@mui/material/Grid';
|
||||
|
||||
// ** Icons Imports
|
||||
import CartPlus from 'mdi-material-ui/CartPlus';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Stack } from '@mui/material';
|
||||
import { CartContext } from 'src/contexts/cart';
|
||||
import TextSnippetIcon from '@mui/icons-material/TextSnippet';
|
||||
|
||||
// Styled Grid component
|
||||
const StyledGrid = styled(Grid)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
[theme.breakpoints.down('md')]: {
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
borderRight: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
}));
|
||||
|
||||
const CardProduct = ({ product, i }) => {
|
||||
let router = useRouter();
|
||||
const { addToCart } = useContext(CartContext);
|
||||
|
||||
if (typeof window === 'undefined') return null;
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Grid container spacing={6}>
|
||||
<StyledGrid item md={5} xs={12}>
|
||||
<CardContent sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
minWidth: '100px',
|
||||
minHeight: '100px',
|
||||
backgroundImage: `url('/api/files/get?dir_prefix=${product.product_image}')`,
|
||||
backgroundSize: 'contain',
|
||||
backgroundPosition: 'center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
}}
|
||||
/>
|
||||
</CardContent>
|
||||
</StyledGrid>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
md={7}
|
||||
sx={{
|
||||
paddingTop: ['0 !important', '0 !important', '1.5rem !important'],
|
||||
paddingLeft: ['1.5rem !important', '1.5rem !important', '0 !important'],
|
||||
}}
|
||||
>
|
||||
<CardContent>
|
||||
<Stack direction="column">
|
||||
<Typography variant="caption" sx={{ marginBottom: 2 }}>
|
||||
{product.name}
|
||||
</Typography>
|
||||
|
||||
<Typography variant="caption" sx={{ fontWeight: 500, marginBottom: 3 }}>
|
||||
Price:{' '}
|
||||
<Box component="span" sx={{ fontWeight: 'bold' }}>
|
||||
${parseInt(product.price).toFixed(2)}
|
||||
</Box>
|
||||
</Typography>
|
||||
|
||||
<Typography variant="caption" sx={{ fontWeight: 500, marginBottom: 3 }}>
|
||||
Remains:{' '}
|
||||
<Box component="span" sx={{ fontWeight: 'bold' }}>
|
||||
{product.count}
|
||||
</Box>
|
||||
</Typography>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
<CardActions className="card-action-dense">
|
||||
<Stack direction="row" spacing={'1rem'} justifyContent={'flex-end'} sx={{ width: '100%' }}>
|
||||
<Box>
|
||||
<Button
|
||||
size="small"
|
||||
variant="contained"
|
||||
disabled={product.unsold_count < 1}
|
||||
onClick={() => {
|
||||
addToCart(product.pid, 1, parseInt(product.price));
|
||||
}}
|
||||
startIcon={<CartPlus />}
|
||||
>
|
||||
{product.unsold_count < 1 ? 'sold out' : 'Add'}
|
||||
</Button>
|
||||
</Box>
|
||||
<Box>
|
||||
<Button
|
||||
size="small"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
router.push(`/shopfront/product/${product.pid}`);
|
||||
}}
|
||||
startIcon={<TextSnippetIcon />}
|
||||
>
|
||||
Details
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
</CardActions>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardProduct;
|
@@ -0,0 +1,112 @@
|
||||
// ** MUI Imports
|
||||
import Card from '@mui/material/Card';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Button from '@mui/material/Button';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Box from '@mui/material/Box';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
|
||||
// ** Icons Imports
|
||||
import { Stack } from '@mui/material';
|
||||
import AddShoppingCartIcon from '@mui/icons-material/AddShoppingCart';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { CartContext } from 'src/contexts/cart';
|
||||
import fetchProduct from 'src/api/fetchProduct';
|
||||
import Loading from 'src/components/Loading';
|
||||
|
||||
const CardProductDetail = () => {
|
||||
const router = useRouter();
|
||||
const { pid } = router.query;
|
||||
const [product, setProduct] = useState(null);
|
||||
|
||||
const { addToCart } = useContext(CartContext);
|
||||
|
||||
useEffect(() => {
|
||||
const update = async () => {
|
||||
let response = await fetchProduct({ pid });
|
||||
let { data } = response;
|
||||
let { product } = data;
|
||||
setProduct(product);
|
||||
};
|
||||
if (pid) update();
|
||||
}, [pid]);
|
||||
|
||||
if (!product)
|
||||
return (
|
||||
<>
|
||||
<Loading />
|
||||
</>
|
||||
);
|
||||
|
||||
// help avoid pre-rendering
|
||||
if (typeof window === 'undefined') return null;
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Grid container spacing={6}>
|
||||
<Grid
|
||||
item
|
||||
sm={5}
|
||||
xs={12}
|
||||
sx={{ paddingTop: ['0 !important', '1.5rem !important'], paddingLeft: ['1.5rem !important', '0 !important'] }}
|
||||
>
|
||||
<CardContent
|
||||
sx={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
textAlign: 'center',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: 'action.hover',
|
||||
padding: theme => `${theme.spacing(18, 5, 16)} !important`,
|
||||
}}
|
||||
>
|
||||
<Stack direction="column" justifyContent={'center'} alignItems={'center'} spacing={'3rem'}>
|
||||
<Box
|
||||
style={{
|
||||
backgroundImage: `url('/api/files/get?dir_prefix=${product.product_image}')`,
|
||||
backgroundSize: 'contain',
|
||||
backgroundPosition: 'center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
width: '300px',
|
||||
minHeight: '300px',
|
||||
borderRadius: '10px',
|
||||
}}
|
||||
></Box>
|
||||
<Box sx={{ mb: 3.5, display: 'flex', alignItems: 'flex-end', justifyContent: 'center' }}>
|
||||
<Typography variant="h6">HKD $</Typography>
|
||||
<Typography variant="h6" sx={{ lineHeight: 1, fontWeight: 600, fontSize: '3.75rem !important' }}>
|
||||
{parseInt(product.price).toFixed(2)}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography variant="body2" sx={{ mb: 13.75, display: 'flex', flexDirection: 'column' }}></Typography>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={7}>
|
||||
<CardContent sx={{ padding: theme => `${theme.spacing(3.25, 5.75, 6.25)} !important` }}>
|
||||
<Typography variant="h6" sx={{ marginBottom: 3.5 }}>
|
||||
{product.name}
|
||||
</Typography>
|
||||
<Typography variant="body2">{product.description}</Typography>
|
||||
<Divider sx={{ marginTop: 6.5, marginBottom: 6.75 }} />
|
||||
<Stack direction="row" justifyContent={'flex-end'}>
|
||||
<Button
|
||||
disabled={product.unsold_count < 1}
|
||||
variant="contained"
|
||||
onClick={() => addToCart(pid, 1, parseInt(product.price))}
|
||||
>
|
||||
<AddShoppingCartIcon />
|
||||
{product.unsold_count < 1 ? 'sold out' : 'Add to cart'}
|
||||
</Button>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardProductDetail;
|
@@ -0,0 +1,165 @@
|
||||
// ** React Imports
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box';
|
||||
import Card from '@mui/material/Card';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import CardActions from '@mui/material/CardActions';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
|
||||
import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline';
|
||||
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
|
||||
|
||||
// ** Icons Imports
|
||||
import { Stack, TextField } from '@mui/material';
|
||||
import { CartContext } from 'src/contexts/cart';
|
||||
|
||||
// Styled Grid component
|
||||
const StyledGrid = styled(Grid)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
[theme.breakpoints.down('md')]: {
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
borderRight: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
}));
|
||||
|
||||
const CartItemDetail = ({ checking_out, products, pid, qty }) => {
|
||||
let [product, setProduct] = useState(null);
|
||||
|
||||
const { addToCart, removeFromCart, total_price, changeCartItemQty } = useContext(CartContext);
|
||||
|
||||
const qtyRef = React.useRef();
|
||||
|
||||
const handleSelectAll = () => {
|
||||
qtyRef.current.select();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let result = products.filter(p => p.pid === pid);
|
||||
console.log({ result, pid, products });
|
||||
setProduct(result[0]);
|
||||
}, [pid]);
|
||||
|
||||
if (!product) return <>Updating product</>;
|
||||
|
||||
return (
|
||||
<Card sx={{ width: '500px' }}>
|
||||
<Grid container spacing={6}>
|
||||
<StyledGrid item md={5} xs={12}>
|
||||
<CardContent sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
minWidth: '100px',
|
||||
minHeight: '100px',
|
||||
backgroundImage: `url('/api/files/get?dir_prefix=${product.product_image}')`,
|
||||
backgroundSize: 'contain',
|
||||
backgroundPosition: 'center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
}}
|
||||
/>
|
||||
</CardContent>
|
||||
</StyledGrid>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
md={7}
|
||||
sx={{
|
||||
paddingTop: ['0 !important', '0 !important', '1.5rem !important'],
|
||||
paddingLeft: ['1.5rem !important', '1.5rem !important', '0 !important'],
|
||||
}}
|
||||
>
|
||||
<CardContent>
|
||||
<Typography variant="h6" sx={{ marginBottom: 2 }}>
|
||||
{product.name}
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ marginBottom: 3.5 }}>
|
||||
{product.description}
|
||||
</Typography>
|
||||
<Typography sx={{ fontWeight: 500, marginBottom: 3 }}>
|
||||
Price:{' '}
|
||||
<Box component="span" sx={{ fontWeight: 'bold' }}>
|
||||
${parseInt(product.price).toFixed(2)}
|
||||
</Box>
|
||||
</Typography>
|
||||
</CardContent>
|
||||
|
||||
<CardActions>
|
||||
<Stack direction="row" justifyContent={'flex-end'} style={{ width: '100%' }}>
|
||||
<Stack sx={{ display: 'flex', flexDirection: 'row', justifyContent: 'flex-end' }}>
|
||||
<Box flexGrow={10} backgroundColor="pink"></Box>
|
||||
<IconButton
|
||||
disabled={checking_out}
|
||||
id="long-button"
|
||||
aria-label="share"
|
||||
aria-haspopup="true"
|
||||
onClick={() => addToCart(pid, 1, parseInt(product.price))}
|
||||
aria-controls="long-menu"
|
||||
>
|
||||
<AddCircleOutlineIcon fontSize="small" />
|
||||
</IconButton>
|
||||
|
||||
<Box textAlign={'center'} width={'2rem'}>
|
||||
<TextField
|
||||
disabled={checking_out}
|
||||
inputRef={qtyRef}
|
||||
variant="standard"
|
||||
value={qty}
|
||||
inputProps={{ style: { textAlign: 'center' } }}
|
||||
onChange={e => {
|
||||
try {
|
||||
let final_qty = parseInt(e.target.value);
|
||||
changeCartItemQty(pid, final_qty, product.price);
|
||||
} catch (error) {
|
||||
console.error("user wasn't entered a number");
|
||||
}
|
||||
}}
|
||||
onBlur={e => {
|
||||
try {
|
||||
let final_qty = parseInt(e.target.value);
|
||||
changeCartItemQty(pid, final_qty, product.price);
|
||||
} catch (error) {
|
||||
console.error("user wasn't entered a number");
|
||||
}
|
||||
}}
|
||||
onClick={handleSelectAll}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<IconButton
|
||||
disabled={checking_out}
|
||||
id="long-button"
|
||||
aria-label="share"
|
||||
aria-haspopup="true"
|
||||
onClick={() => removeFromCart(pid)}
|
||||
aria-controls="long-menu"
|
||||
>
|
||||
{qty == 1 ? (
|
||||
<>
|
||||
<DeleteOutlineIcon fontSize="small" color={'error'} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<RemoveCircleOutlineIcon fontSize="small" />
|
||||
</>
|
||||
)}
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</CardActions>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default CartItemDetail;
|
78
tsc1877/task1/aws/workspace/admin/src/components/Checkout.js
Normal file
78
tsc1877/task1/aws/workspace/admin/src/components/Checkout.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { PayPalButtons, usePayPalScriptReducer } from '@paypal/react-paypal-js';
|
||||
import { useRouter } from 'next/router';
|
||||
import { CartContext } from 'src/contexts/cart';
|
||||
import SaveOrder from 'src/api/saveOrder';
|
||||
import GetOrderDetails from 'src/api/getOrderDetails';
|
||||
import CancelOrder from 'src/api/cancelOrder';
|
||||
|
||||
const Checkout = () => {
|
||||
const router = useRouter();
|
||||
const { cart, total_price, products, proceedCheckOutCart, emptyCart } = useContext(CartContext);
|
||||
const [{ options, isPending }, dispatch] = usePayPalScriptReducer();
|
||||
const currency_code = 'HKD';
|
||||
const [custom_id, setCustomId] = useState('');
|
||||
const share = {};
|
||||
|
||||
const onCreateOrder = async (data, actions) => {
|
||||
const proceed = async () => {
|
||||
try {
|
||||
let { order_details } = await GetOrderDetails({ cart, currency_code });
|
||||
|
||||
share['custom_id'] = order_details['custom_id'];
|
||||
return actions.order.create({ purchase_units: [{ amount: { value: total_price } }] });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
return await proceed();
|
||||
};
|
||||
|
||||
const onCancelOrder = async (data, actions) => {
|
||||
const cancel = async () => {
|
||||
try {
|
||||
await CancelOrder({ custom_id: share['custom_id'] });
|
||||
alert('Your order has been cancelled');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
return await cancel();
|
||||
};
|
||||
|
||||
const onApproveOrder = (data, actions) => {
|
||||
return actions.order
|
||||
.capture()
|
||||
.then(async details => {
|
||||
let { custom_id } = share;
|
||||
await SaveOrder({ custom_id });
|
||||
return await emptyCart();
|
||||
})
|
||||
.then(() => {
|
||||
(async () => {
|
||||
await proceedCheckOutCart();
|
||||
router.replace('/shopfront/cart/Thankyou');
|
||||
})();
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="checkout">
|
||||
{isPending ? (
|
||||
<p>LOADING...</p>
|
||||
) : (
|
||||
<>
|
||||
<PayPalButtons
|
||||
style={{ layout: 'vertical' }}
|
||||
createOrder={(data, actions) => onCreateOrder(data, actions)}
|
||||
onApprove={(data, actions) => onApproveOrder(data, actions)}
|
||||
onCancel={(data, actions) => onCancelOrder(data, actions)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Checkout;
|
@@ -0,0 +1,99 @@
|
||||
// ** MUI Imports
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Table from '@mui/material/Table';
|
||||
import TableRow from '@mui/material/TableRow';
|
||||
import TableHead from '@mui/material/TableHead';
|
||||
import TableBody from '@mui/material/TableBody';
|
||||
import TableCell from '@mui/material/TableCell';
|
||||
import TableContainer from '@mui/material/TableContainer';
|
||||
import NotesIcon from '@mui/icons-material/Notes';
|
||||
import crypto from 'crypto';
|
||||
import { Box, Stack, Typography } from '@mui/material';
|
||||
import { useEffect, useState } from 'react';
|
||||
import fetchCustomerOrders from 'src/api/fetchCustomerOrders';
|
||||
import Loading from './Loading';
|
||||
import NoOrders from './NoOrders';
|
||||
|
||||
const CustomerOrderTable = () => {
|
||||
let [orders, setOrders] = useState(null);
|
||||
let [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchOrder = async () => {
|
||||
try {
|
||||
let session_raw = localStorage.getItem('session');
|
||||
let { session } = JSON.parse(session_raw);
|
||||
let fetch_orders = await fetchCustomerOrders({ session });
|
||||
setOrders(fetch_orders);
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error('error during fetching orders');
|
||||
}
|
||||
};
|
||||
fetchOrder();
|
||||
}, []);
|
||||
|
||||
if (loading) return <Loading />;
|
||||
|
||||
if (!orders || orders.length == 0) return <NoOrders />;
|
||||
|
||||
return (
|
||||
<TableContainer component={Paper} sx={{ minWidth: '66vw' }}>
|
||||
<Table sx={{ width: '100%', minWidth: 650 }} aria-label="simple table">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="center"></TableCell>
|
||||
{/* <TableCell align="center">custom_id</TableCell> */}
|
||||
{/* <TableCell align="center">username</TableCell> */}
|
||||
<TableCell align="center">invoice_id</TableCell>
|
||||
<TableCell align="center">currency</TableCell>
|
||||
<TableCell align="center">order status</TableCell>
|
||||
<TableCell align="center">amount</TableCell>
|
||||
<TableCell align="center">items</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{orders.map(row => (
|
||||
<TableRow
|
||||
key={row.name}
|
||||
sx={{
|
||||
'&:last-of-type td, &:last-of-type th': {
|
||||
border: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TableCell component="th" scope="row">
|
||||
<NotesIcon />
|
||||
</TableCell>
|
||||
{/* <TableCell align="right">{row.custom_id}</TableCell> */}
|
||||
{/* <TableCell align="right">{row.username}</TableCell> */}
|
||||
<TableCell align="right">{row.invoice_id}</TableCell>
|
||||
<TableCell align="right">{row.currency_code}</TableCell>
|
||||
<TableCell align="right">{row.order_status}</TableCell>
|
||||
<TableCell align="right">{parseInt(row.amount).toFixed(2)}</TableCell>
|
||||
<TableCell align="right">
|
||||
{JSON.parse(row.items).map(i => (
|
||||
<>
|
||||
<Stack direction="column" spacing={'0.2rem'} alignItems={'flex-start'}>
|
||||
<Typography variant="caption" fontWeight={'bold'}>
|
||||
{i.item_name}
|
||||
</Typography>
|
||||
<Typography variant="caption" fontWeight={'bold'}>
|
||||
{'QTY :' + i.quantity}
|
||||
</Typography>
|
||||
<Typography variant="caption" fontWeight={'bold'}>
|
||||
{row.currency_code + ' ' + parseInt(i.unit_price).toFixed(2)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</>
|
||||
))}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomerOrderTable;
|
13
tsc1877/task1/aws/workspace/admin/src/components/Loading.js
Normal file
13
tsc1877/task1/aws/workspace/admin/src/components/Loading.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Stack, Typography } from '@mui/material';
|
||||
|
||||
const Loading = () => {
|
||||
return (
|
||||
<>
|
||||
<Stack direction="column" height="50vh" justifyContent={'center'} alignItems={'center'}>
|
||||
<Typography variant="h6">loading ...</Typography>
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Loading;
|
15
tsc1877/task1/aws/workspace/admin/src/components/NoOrders.js
Normal file
15
tsc1877/task1/aws/workspace/admin/src/components/NoOrders.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Paper, Stack, TableContainer, Typography } from '@mui/material';
|
||||
|
||||
const NoOrders = () => {
|
||||
return (
|
||||
<>
|
||||
<TableContainer component={Paper} sx={{ minWidth: '66vw', minHeight: '66vh' }}>
|
||||
<Stack direction="column" height="50vh" justifyContent={'center'} alignItems={'center'}>
|
||||
<Typography variant="h6">NoOrders ...</Typography>
|
||||
</Stack>
|
||||
</TableContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NoOrders;
|
@@ -0,0 +1,16 @@
|
||||
import { Box, Stack, Typography } from '@mui/material';
|
||||
import SwapHorizontalCircleIcon from '@mui/icons-material/SwapHorizontalCircle';
|
||||
const Redirecting = () => {
|
||||
return (
|
||||
<>
|
||||
<Box>
|
||||
<Stack minHeight={'50vh'} spacing="1rem" direction="column" justifyContent="center" alignItems="center">
|
||||
<SwapHorizontalCircleIcon />
|
||||
<Typography variant="h6">Redirecting ...</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Redirecting;
|
16
tsc1877/task1/aws/workspace/admin/src/configs/themeConfig.js
Normal file
16
tsc1877/task1/aws/workspace/admin/src/configs/themeConfig.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const themeConfig = {
|
||||
// ** Layout Configs
|
||||
templateName: 'VTKH MALL' /* App Name */,
|
||||
mode: 'light' /* light | dark */,
|
||||
contentWidth: 'boxed' /* full | boxed */,
|
||||
// ** Routing Configs
|
||||
routingLoader: true /* true | false */,
|
||||
// ** Navigation (Menu) Configs
|
||||
menuTextTruncate: true /* true | false */,
|
||||
navigationSize: 260 /* Number in PX(Pixels) /*! Note: This is for Vertical navigation menu only */,
|
||||
// ** Other Configs
|
||||
responsiveFontSizes: true /* true | false */,
|
||||
disableRipple: false /* true | false */,
|
||||
};
|
||||
|
||||
export default themeConfig;
|
99
tsc1877/task1/aws/workspace/admin/src/contexts/auth.js
Normal file
99
tsc1877/task1/aws/workspace/admin/src/contexts/auth.js
Normal file
@@ -0,0 +1,99 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { createContext, useEffect, useState } from 'react';
|
||||
import CheckSession from 'src/api/checkSession';
|
||||
import Loading from 'src/components/Loading';
|
||||
|
||||
const AuthContext = createContext();
|
||||
|
||||
const AuthProvider = ({ children }) => {
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||
const [username, setUsername] = useState(null);
|
||||
const router = useRouter();
|
||||
|
||||
const performLogin = ({ values }) => {
|
||||
return fetch('/api/auth/login', { method: 'POST', body: JSON.stringify(values) })
|
||||
.then(res => res.json())
|
||||
.then(res_json => {
|
||||
let { status, username: username_found } = res_json;
|
||||
setUsername(username_found);
|
||||
|
||||
if (status == 'admin login OK') {
|
||||
localStorage.setItem('session', JSON.stringify(res_json));
|
||||
|
||||
router.replace('/admin');
|
||||
} else if (status == 'customer login OK') {
|
||||
localStorage.setItem('session', JSON.stringify(res_json));
|
||||
router.replace('/shopfront/customer/profile');
|
||||
} else {
|
||||
alert('Invalid username or password');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
const performLogout = () => {
|
||||
setUsername(null);
|
||||
localStorage.clear('session');
|
||||
};
|
||||
|
||||
const performChangePassword = ({ old_password, new_password }) => {
|
||||
return fetch('/api/auth/change_password', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ username, old_password, new_password }),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res_json => {
|
||||
let { status } = res_json;
|
||||
|
||||
if (status == 'password change ok') {
|
||||
performLogout();
|
||||
router.replace('/shopfront');
|
||||
} else {
|
||||
alert('password change failed');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
let [loading, setLoading] = useState(true);
|
||||
useEffect(() => {
|
||||
let session_string = localStorage.getItem('session');
|
||||
if (session_string) {
|
||||
let { session } = JSON.parse(session_string);
|
||||
|
||||
CheckSession({ session }).then(data => {
|
||||
let { username: username_found } = data;
|
||||
setUsername(username_found);
|
||||
});
|
||||
setLoading(false);
|
||||
} else {
|
||||
setLoading(false);
|
||||
router.replace('/shopfront');
|
||||
}
|
||||
}, []);
|
||||
|
||||
const helloworld = () => {
|
||||
console.log('helloworld');
|
||||
};
|
||||
|
||||
if (loading)
|
||||
return (
|
||||
<>
|
||||
<Loading />
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider
|
||||
value={{ username, setUsername, isAuthenticated, performLogin, performLogout, performChangePassword, helloworld }}
|
||||
>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export { AuthContext, AuthProvider };
|
149
tsc1877/task1/aws/workspace/admin/src/contexts/cart.js
Normal file
149
tsc1877/task1/aws/workspace/admin/src/contexts/cart.js
Normal file
@@ -0,0 +1,149 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { createContext, useEffect, useState } from 'react';
|
||||
import checkoutCart from 'src/api/checkoutCart';
|
||||
import fetchProducts from 'src/api/fetchProducts';
|
||||
|
||||
const CartContext = createContext();
|
||||
const CartConsumer = CartContext.Consumer;
|
||||
|
||||
const CartProvider = ({ children }) => {
|
||||
const [cart, setCart] = useState([]);
|
||||
const [total_price, setTotalPrice] = useState(0);
|
||||
const [products, setProducts] = useState([]);
|
||||
|
||||
const changeCartItemQty = (pid, quantity, unit_price) => {
|
||||
if (quantity < 1) {
|
||||
alert('please enter a number greater than 0');
|
||||
} else {
|
||||
const productExistInCart = cart.find(item => item.pid === pid);
|
||||
|
||||
if (productExistInCart) {
|
||||
const max_item_allowed = products.filter(p => p.pid === pid)[0].count;
|
||||
|
||||
const item = cart.find(item => item.pid === pid);
|
||||
const allow_to_add_item = quantity <= max_item_allowed;
|
||||
|
||||
if (allow_to_add_item) {
|
||||
const final_item = quantity;
|
||||
setCart(cart.map(item => (item.pid === pid ? { ...item, quantity: final_item, unit_price } : item)));
|
||||
} else {
|
||||
// display alert ?
|
||||
alert('sorry but the item to add is over the max item allowed');
|
||||
}
|
||||
} else {
|
||||
console.log('newly insert in cart');
|
||||
setCart([...cart, { pid, quantity, unit_price }]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const addToCart = (pid, quantity, unit_price) => {
|
||||
if (cart) {
|
||||
const productExistInCart = cart.find(item => item.pid === pid);
|
||||
|
||||
if (productExistInCart) {
|
||||
const max_item_allowed = products.filter(p => p.pid === pid)[0].unsold_count;
|
||||
|
||||
// extract item from cart
|
||||
const item = cart.find(item => item.pid === pid);
|
||||
const allow_to_add_item = item.quantity + quantity <= max_item_allowed;
|
||||
|
||||
if (allow_to_add_item) {
|
||||
const final_item = item.quantity + quantity;
|
||||
setCart(cart.map(item => (item.pid === pid ? { ...item, quantity: final_item, unit_price } : item)));
|
||||
} else {
|
||||
// display alert ?
|
||||
alert('sorry but the item to add is over the max item allowed');
|
||||
}
|
||||
} else {
|
||||
setCart([...cart, { pid, quantity, unit_price }]);
|
||||
}
|
||||
} else {
|
||||
setCart([{ pid, quantity, unit_price }]);
|
||||
}
|
||||
};
|
||||
|
||||
const emptyCart = () => {
|
||||
setCart([]);
|
||||
};
|
||||
|
||||
const proceedCheckOutCart = async () => {
|
||||
try {
|
||||
let { data } = await checkoutCart(cart);
|
||||
|
||||
if (data.status === 'OK') {
|
||||
// clear cart after done
|
||||
localStorage.setItem('cart', JSON.stringify([]));
|
||||
} else {
|
||||
console.error({ data });
|
||||
throw new Error('error during checkout');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
console.error('checkout error');
|
||||
}
|
||||
};
|
||||
|
||||
// localStorage for saving and loading across sessions
|
||||
// loading, on each fresh site arriving
|
||||
useEffect(() => {
|
||||
setCart(JSON.parse(localStorage.getItem('cart')));
|
||||
}, []);
|
||||
|
||||
// saving, trigger on each cart update
|
||||
useEffect(() => {
|
||||
if (cart?.length > 0) {
|
||||
let temp = 0;
|
||||
cart.forEach(c_i => {
|
||||
temp = temp + c_i.unit_price * c_i.quantity;
|
||||
console.log(c_i.unit_price * c_i.quantity);
|
||||
});
|
||||
setTotalPrice(temp);
|
||||
} else {
|
||||
setTotalPrice(0);
|
||||
}
|
||||
|
||||
localStorage.setItem('cart', JSON.stringify(cart));
|
||||
}, [cart]);
|
||||
|
||||
const removeFromCart = pid => {
|
||||
const productToRemove = cart.find(item => item.pid === pid);
|
||||
if (productToRemove.quantity > 1) {
|
||||
setCart(cart.map(item => (item.pid === pid ? { ...item, quantity: item.quantity - 1 } : item)));
|
||||
} else {
|
||||
setCart(cart.filter(item => item.pid !== pid));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const update = async () => {
|
||||
let temp = await fetchProducts();
|
||||
setProducts(temp);
|
||||
};
|
||||
update();
|
||||
}, []);
|
||||
|
||||
const helloworld = () => {
|
||||
console.log('hello cart');
|
||||
};
|
||||
|
||||
return (
|
||||
<CartContext.Provider
|
||||
value={{
|
||||
addToCart,
|
||||
removeFromCart,
|
||||
helloworld,
|
||||
emptyCart,
|
||||
cart,
|
||||
total_price,
|
||||
changeCartItemQty,
|
||||
products,
|
||||
proceedCheckOutCart,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</CartContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export { CartProvider, CartConsumer, CartContext };
|
70
tsc1877/task1/aws/workspace/admin/src/layouts/UserLayout.js
Normal file
70
tsc1877/task1/aws/workspace/admin/src/layouts/UserLayout.js
Normal file
@@ -0,0 +1,70 @@
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
|
||||
// ** Layout Imports
|
||||
// !Do not remove this Layout import
|
||||
import VerticalLayout from 'src/@core/layouts/VerticalLayout';
|
||||
|
||||
// ** Navigation Imports
|
||||
import VerticalNavItems from 'src/navigation/vertical';
|
||||
|
||||
// ** Component Import
|
||||
import UpgradeToProButton from './components/UpgradeToProButton';
|
||||
import VerticalAppBarContent from './components/vertical/AppBarContent';
|
||||
|
||||
// ** Hook Import
|
||||
import { useSettings } from 'src/@core/hooks/useSettings';
|
||||
|
||||
const UserLayout = ({ children }) => {
|
||||
// ** Hooks
|
||||
const { settings, saveSettings } = useSettings();
|
||||
|
||||
/**
|
||||
* The below variable will hide the current layout menu at given screen size.
|
||||
* The menu will be accessible from the Hamburger icon only (Vertical Overlay Menu).
|
||||
* You can change the screen size from which you want to hide the current layout menu.
|
||||
* Please refer useMediaQuery() hook: https://mui.com/components/use-media-query/,
|
||||
* to know more about what values can be passed to this hook.
|
||||
* ! Do not change this value unless you know what you are doing. It can break the template.
|
||||
*/
|
||||
const hidden = useMediaQuery(theme => theme.breakpoints.down('lg'));
|
||||
|
||||
const UpgradeToProImg = () => {
|
||||
return (
|
||||
<Box sx={{ mx: 'auto' }}>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://themeselection.com/products/materio-mui-react-nextjs-admin-template/"
|
||||
>
|
||||
<img width={230} alt="upgrade to premium" src={`/images/misc/upgrade-banner-${settings.mode}.png`} />
|
||||
</a>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<VerticalLayout
|
||||
hidden={hidden}
|
||||
settings={settings}
|
||||
saveSettings={saveSettings}
|
||||
verticalNavItems={VerticalNavItems()} // Navigation Items
|
||||
verticalAppBarContent={(
|
||||
props, // AppBar Content
|
||||
) => (
|
||||
<VerticalAppBarContent
|
||||
hidden={hidden}
|
||||
settings={settings}
|
||||
saveSettings={saveSettings}
|
||||
toggleNavVisibility={props.toggleNavVisibility}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
{/* <UpgradeToProButton /> */}
|
||||
</VerticalLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserLayout;
|
@@ -0,0 +1,111 @@
|
||||
// ** React Import
|
||||
import { useState } from 'react';
|
||||
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box';
|
||||
import Fade from '@mui/material/Fade';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Button from '@mui/material/Button';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
|
||||
// ** Third Party Imports
|
||||
import { usePopper } from 'react-popper';
|
||||
|
||||
const BuyNowButton = () => {
|
||||
// ** States
|
||||
const [open, setOpen] = useState(false);
|
||||
const [popperElement, setPopperElement] = useState(null);
|
||||
const [referenceElement, setReferenceElement] = useState(null);
|
||||
|
||||
const { styles, attributes, update } = usePopper(referenceElement, popperElement, {
|
||||
placement: 'top-end',
|
||||
});
|
||||
|
||||
const handleOpen = () => {
|
||||
setOpen(true);
|
||||
update ? update() : null;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
className="upgrade-to-pro-button mui-fixed"
|
||||
sx={{ right: theme => theme.spacing(20), bottom: theme => theme.spacing(10), zIndex: 11, position: 'fixed' }}
|
||||
>
|
||||
<Button
|
||||
component="a"
|
||||
target="_blank"
|
||||
variant="contained"
|
||||
onMouseEnter={handleOpen}
|
||||
onMouseLeave={handleClose}
|
||||
ref={e => setReferenceElement(e)}
|
||||
href="https://themeselection.com/products/materio-mui-react-nextjs-admin-template/"
|
||||
sx={{
|
||||
backgroundColor: '#ff3e1d',
|
||||
boxShadow: '0 1px 20px 1px #ff3e1d',
|
||||
'&:hover': {
|
||||
boxShadow: 'none',
|
||||
backgroundColor: '#e6381a',
|
||||
},
|
||||
}}
|
||||
>
|
||||
Upgrade To Pro
|
||||
</Button>
|
||||
<Fade in={open} timeout={700}>
|
||||
<Box
|
||||
style={styles.popper}
|
||||
ref={setPopperElement}
|
||||
{...attributes.popper}
|
||||
onMouseEnter={handleOpen}
|
||||
onMouseLeave={handleClose}
|
||||
sx={{ pb: 4, minWidth: theme => (theme.breakpoints.down('sm') ? 400 : 300) }}
|
||||
>
|
||||
<Paper elevation={9} sx={{ borderRadius: 1, overflow: 'hidden' }}>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://themeselection.com/products/materio-mui-react-nextjs-admin-template/"
|
||||
>
|
||||
<img width="100%" alt="materio-pro-banner" src="/images/misc/materio-pro-banner.png" />
|
||||
</a>
|
||||
<CardContent>
|
||||
<Typography sx={{ mb: 4 }} variant="h6">
|
||||
Materio - React Admin Template
|
||||
</Typography>
|
||||
<Typography sx={{ mb: 4 }} variant="body2">
|
||||
Materio Admin is the most developer friendly & highly customizable Admin Dashboard Template based on MUI
|
||||
and NextJS.
|
||||
</Typography>
|
||||
<Typography sx={{ mb: 4 }} variant="body2">
|
||||
Click on below buttons to explore PRO version.
|
||||
</Typography>
|
||||
<Button
|
||||
component="a"
|
||||
sx={{ mr: 4 }}
|
||||
target="_blank"
|
||||
variant="contained"
|
||||
href="https://demos.themeselection.com/materio-mui-react-nextjs-admin-template/landing/"
|
||||
>
|
||||
Demo
|
||||
</Button>
|
||||
<Button
|
||||
component="a"
|
||||
target="_blank"
|
||||
variant="outlined"
|
||||
href="https://themeselection.com/products/materio-mui-react-nextjs-admin-template/"
|
||||
>
|
||||
Download
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Fade>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default BuyNowButton;
|
@@ -0,0 +1,15 @@
|
||||
const UserIcon = props => {
|
||||
// ** Props
|
||||
const { icon, iconProps } = props;
|
||||
const IconTag = icon;
|
||||
let styles;
|
||||
|
||||
/* styles = {
|
||||
color: 'red',
|
||||
fontSize: '2rem'
|
||||
} */
|
||||
// @ts-ignore
|
||||
return <IconTag {...iconProps} style={{ ...styles }} />;
|
||||
};
|
||||
|
||||
export default UserIcon;
|
@@ -0,0 +1,44 @@
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
import InputAdornment from '@mui/material/InputAdornment';
|
||||
|
||||
// ** Icons Imports
|
||||
import Menu from 'mdi-material-ui/Menu';
|
||||
import Magnify from 'mdi-material-ui/Magnify';
|
||||
|
||||
// ** Components
|
||||
import ModeToggler from 'src/@core/layouts/components/shared-components/ModeToggler';
|
||||
import UserDropdown from 'src/@core/layouts/components/shared-components/UserDropdown';
|
||||
import NotificationDropdown from 'src/@core/layouts/components/shared-components/NotificationDropdown';
|
||||
|
||||
const AppBarContent = props => {
|
||||
// ** Props
|
||||
const { hidden, settings, saveSettings, toggleNavVisibility } = props;
|
||||
|
||||
// ** Hook
|
||||
const hiddenSm = useMediaQuery(theme => theme.breakpoints.down('sm'));
|
||||
|
||||
return (
|
||||
<Box sx={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Box className="actions-left" sx={{ mr: 2, display: 'flex', alignItems: 'center' }}>
|
||||
{hidden ? (
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={toggleNavVisibility}
|
||||
sx={{ ml: -2.75, ...(hiddenSm ? {} : { mr: 3.5 }) }}
|
||||
>
|
||||
<Menu />
|
||||
</IconButton>
|
||||
) : null}
|
||||
</Box>
|
||||
<Box className="actions-right" sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<UserDropdown />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppBarContent;
|
@@ -0,0 +1,27 @@
|
||||
// ** Icon imports
|
||||
import Login from 'mdi-material-ui/Login';
|
||||
import Table from 'mdi-material-ui/Table';
|
||||
import CubeOutline from 'mdi-material-ui/CubeOutline';
|
||||
import HomeOutline from 'mdi-material-ui/HomeOutline';
|
||||
import FormatLetterCase from 'mdi-material-ui/FormatLetterCase';
|
||||
import AccountCogOutline from 'mdi-material-ui/AccountCogOutline';
|
||||
import CreditCardOutline from 'mdi-material-ui/CreditCardOutline';
|
||||
import AccountPlusOutline from 'mdi-material-ui/AccountPlusOutline';
|
||||
import AlertCircleOutline from 'mdi-material-ui/AlertCircleOutline';
|
||||
import GoogleCirclesExtended from 'mdi-material-ui/GoogleCirclesExtended';
|
||||
|
||||
const navigation = () => {
|
||||
return [
|
||||
{ title: 'Shop front', icon: HomeOutline, path: '/' },
|
||||
|
||||
{ sectionTitle: 'Testing' },
|
||||
{ title: 'Categories', icon: Table, path: '/admin/categories' },
|
||||
{ title: 'Products', icon: Table, path: '/admin/products' },
|
||||
{ title: 'Inventory', icon: Table, path: '/admin/inventory' },
|
||||
{ title: 'Order', icon: Table, path: '/admin/order' },
|
||||
{ title: 'Documentation', icon: Table, path: '/admin/documentation' },
|
||||
{ title: 'Logout', icon: Table, path: '/admin/logout' },
|
||||
];
|
||||
};
|
||||
|
||||
export default navigation;
|
61
tsc1877/task1/aws/workspace/admin/src/pages/401.js
Normal file
61
tsc1877/task1/aws/workspace/admin/src/pages/401.js
Normal file
@@ -0,0 +1,61 @@
|
||||
// ** Next Import
|
||||
import Link from 'next/link';
|
||||
|
||||
// ** MUI Components
|
||||
import Button from '@mui/material/Button';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
// ** Layout Import
|
||||
import BlankLayout from 'src/@core/layouts/BlankLayout';
|
||||
|
||||
// ** Demo Imports
|
||||
import FooterIllustrations from 'src/views/pages/misc/FooterIllustrations';
|
||||
|
||||
// ** Styled Components
|
||||
const BoxWrapper = styled(Box)(({ theme }) => ({
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width: '90vw',
|
||||
},
|
||||
}));
|
||||
|
||||
const Img = styled('img')(({ theme }) => ({
|
||||
marginBottom: theme.spacing(10),
|
||||
[theme.breakpoints.down('lg')]: {
|
||||
height: 450,
|
||||
marginTop: theme.spacing(10),
|
||||
},
|
||||
[theme.breakpoints.down('md')]: {
|
||||
height: 400,
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
marginTop: theme.spacing(13),
|
||||
},
|
||||
}));
|
||||
|
||||
const Error401 = () => {
|
||||
return (
|
||||
<Box className="content-center">
|
||||
<Box sx={{ p: 5, display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center' }}>
|
||||
<BoxWrapper>
|
||||
<Typography variant="h1">401</Typography>
|
||||
<Typography variant="h5" sx={{ mb: 1, fontSize: '1.5rem !important' }}>
|
||||
You are not authorized! 🔐
|
||||
</Typography>
|
||||
<Typography variant="body2">You don′t have permission to access this page. Go Home!</Typography>
|
||||
</BoxWrapper>
|
||||
<Img height="487" alt="error-illustration" src="/images/pages/401.png" />
|
||||
<Link passHref href="/">
|
||||
<Button component="a" variant="contained" sx={{ px: 5.5 }}>
|
||||
Back to Home
|
||||
</Button>
|
||||
</Link>
|
||||
</Box>
|
||||
<FooterIllustrations />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
Error401.getLayout = page => <BlankLayout>{page}</BlankLayout>;
|
||||
|
||||
export default Error401;
|
70
tsc1877/task1/aws/workspace/admin/src/pages/404.js
Normal file
70
tsc1877/task1/aws/workspace/admin/src/pages/404.js
Normal file
@@ -0,0 +1,70 @@
|
||||
// ** Next Import
|
||||
import Link from 'next/link';
|
||||
|
||||
// ** MUI Components
|
||||
import Button from '@mui/material/Button';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
// ** Layout Import
|
||||
import BlankLayout from 'src/@core/layouts/BlankLayout';
|
||||
|
||||
// ** Demo Imports
|
||||
import FooterIllustrations from 'src/views/pages/misc/FooterIllustrations';
|
||||
|
||||
// ** Styled Components
|
||||
const BoxWrapper = styled(Box)(({ theme }) => ({
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width: '90vw',
|
||||
},
|
||||
}));
|
||||
|
||||
const Img = styled('img')(({ theme }) => ({
|
||||
marginBottom: theme.spacing(10),
|
||||
[theme.breakpoints.down('lg')]: {
|
||||
height: 450,
|
||||
marginTop: theme.spacing(10),
|
||||
},
|
||||
[theme.breakpoints.down('md')]: {
|
||||
height: 400,
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
marginTop: theme.spacing(13),
|
||||
},
|
||||
}));
|
||||
|
||||
const TreeIllustration = styled('img')(({ theme }) => ({
|
||||
left: 0,
|
||||
bottom: '5rem',
|
||||
position: 'absolute',
|
||||
[theme.breakpoints.down('lg')]: {
|
||||
bottom: 0,
|
||||
},
|
||||
}));
|
||||
|
||||
const Error404 = () => {
|
||||
return (
|
||||
<Box className="content-center">
|
||||
<Box sx={{ p: 5, display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center' }}>
|
||||
<BoxWrapper>
|
||||
<Typography variant="h1">404</Typography>
|
||||
<Typography variant="h5" sx={{ mb: 1, fontSize: '1.5rem !important' }}>
|
||||
Page Not Found ⚠️
|
||||
</Typography>
|
||||
<Typography variant="body2">We couldn′t find the page you are looking for.</Typography>
|
||||
</BoxWrapper>
|
||||
<Img height="487" alt="error-illustration" src="/images/pages/404.png" />
|
||||
<Link passHref href="/">
|
||||
<Button component="a" variant="contained" sx={{ px: 5.5 }}>
|
||||
Back to Home
|
||||
</Button>
|
||||
</Link>
|
||||
</Box>
|
||||
<FooterIllustrations image={<TreeIllustration alt="tree" src="/images/pages/tree.png" />} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
Error404.getLayout = page => <BlankLayout>{page}</BlankLayout>;
|
||||
|
||||
export default Error404;
|
70
tsc1877/task1/aws/workspace/admin/src/pages/500.js
Normal file
70
tsc1877/task1/aws/workspace/admin/src/pages/500.js
Normal file
@@ -0,0 +1,70 @@
|
||||
// ** Next Import
|
||||
import Link from 'next/link';
|
||||
|
||||
// ** MUI Components
|
||||
import Button from '@mui/material/Button';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
// ** Layout Import
|
||||
import BlankLayout from 'src/@core/layouts/BlankLayout';
|
||||
|
||||
// ** Demo Imports
|
||||
import FooterIllustrations from 'src/views/pages/misc/FooterIllustrations';
|
||||
|
||||
// ** Styled Components
|
||||
const BoxWrapper = styled(Box)(({ theme }) => ({
|
||||
[theme.breakpoints.down('md')]: {
|
||||
width: '90vw',
|
||||
},
|
||||
}));
|
||||
|
||||
const Img = styled('img')(({ theme }) => ({
|
||||
marginBottom: theme.spacing(10),
|
||||
[theme.breakpoints.down('lg')]: {
|
||||
height: 450,
|
||||
marginTop: theme.spacing(10),
|
||||
},
|
||||
[theme.breakpoints.down('md')]: {
|
||||
height: 400,
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
marginTop: theme.spacing(13),
|
||||
},
|
||||
}));
|
||||
|
||||
const TreeIllustration = styled('img')(({ theme }) => ({
|
||||
left: 0,
|
||||
bottom: '5rem',
|
||||
position: 'absolute',
|
||||
[theme.breakpoints.down('lg')]: {
|
||||
bottom: 0,
|
||||
},
|
||||
}));
|
||||
|
||||
const Error500 = () => {
|
||||
return (
|
||||
<Box className="content-center">
|
||||
<Box sx={{ p: 5, display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center' }}>
|
||||
<BoxWrapper>
|
||||
<Typography variant="h1">500</Typography>
|
||||
<Typography variant="h5" sx={{ mb: 1, fontSize: '1.5rem !important' }}>
|
||||
Internal server error 👨🏻💻
|
||||
</Typography>
|
||||
<Typography variant="body2">Oops, something went wrong!</Typography>
|
||||
</BoxWrapper>
|
||||
<Img height="487" alt="error-illustration" src="/images/pages/500.png" />
|
||||
<Link passHref href="/">
|
||||
<Button component="a" variant="contained" sx={{ px: 5.5 }}>
|
||||
Back to Home
|
||||
</Button>
|
||||
</Link>
|
||||
</Box>
|
||||
<FooterIllustrations image={<TreeIllustration alt="tree" src="/images/pages/tree-3.png" />} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
Error500.getLayout = page => <BlankLayout>{page}</BlankLayout>;
|
||||
|
||||
export default Error500;
|
78
tsc1877/task1/aws/workspace/admin/src/pages/_app.js
Normal file
78
tsc1877/task1/aws/workspace/admin/src/pages/_app.js
Normal file
@@ -0,0 +1,78 @@
|
||||
// ** Next Imports
|
||||
import Head from 'next/head';
|
||||
import { Router } from 'next/router';
|
||||
|
||||
// ** Loader Import
|
||||
import NProgress from 'nprogress';
|
||||
|
||||
// ** Emotion Imports
|
||||
import { CacheProvider } from '@emotion/react';
|
||||
|
||||
// ** Config Imports
|
||||
import themeConfig from 'src/configs/themeConfig';
|
||||
|
||||
// ** Component Imports
|
||||
import UserLayout from 'src/layouts/UserLayout';
|
||||
import ThemeComponent from 'src/@core/theme/ThemeComponent';
|
||||
|
||||
// ** Contexts
|
||||
import { SettingsConsumer, SettingsProvider } from 'src/@core/context/settingsContext';
|
||||
|
||||
// ** Utils Imports
|
||||
import { createEmotionCache } from 'src/@core/utils/create-emotion-cache';
|
||||
|
||||
// ** React Perfect Scrollbar Style
|
||||
import 'react-perfect-scrollbar/dist/css/styles.css';
|
||||
|
||||
// ** Global css styles
|
||||
import '../../styles/globals.css';
|
||||
import { AuthProvider } from 'src/contexts/auth';
|
||||
|
||||
const clientSideEmotionCache = createEmotionCache();
|
||||
|
||||
// ** Pace Loader
|
||||
if (themeConfig.routingLoader) {
|
||||
Router.events.on('routeChangeStart', () => {
|
||||
NProgress.start();
|
||||
});
|
||||
Router.events.on('routeChangeError', () => {
|
||||
NProgress.done();
|
||||
});
|
||||
Router.events.on('routeChangeComplete', () => {
|
||||
NProgress.done();
|
||||
});
|
||||
}
|
||||
|
||||
// ** Configure JSS & ClassName
|
||||
const App = props => {
|
||||
const { Component, emotionCache = clientSideEmotionCache, pageProps } = props;
|
||||
|
||||
// Variables
|
||||
const getLayout = Component.getLayout ?? (page => <UserLayout>{page}</UserLayout>);
|
||||
|
||||
return (
|
||||
<CacheProvider value={emotionCache}>
|
||||
<Head>
|
||||
<title>{`${themeConfig.templateName} - Material Design React Admin Template`}</title>
|
||||
<meta
|
||||
name="description"
|
||||
content={`${themeConfig.templateName} – Material Design React Admin Dashboard Template – is the most developer friendly & highly customizable Admin Dashboard Template based on MUI v5.`}
|
||||
/>
|
||||
<meta name="keywords" content="Material Design, MUI, Admin Template, React Admin Template" />
|
||||
<meta name="viewport" content="initial-scale=1, width=device-width" />
|
||||
</Head>
|
||||
|
||||
<AuthProvider>
|
||||
<SettingsProvider>
|
||||
<SettingsConsumer>
|
||||
{({ settings }) => {
|
||||
return <ThemeComponent settings={settings}>{getLayout(<Component {...pageProps} />)}</ThemeComponent>;
|
||||
}}
|
||||
</SettingsConsumer>
|
||||
</SettingsProvider>
|
||||
</AuthProvider>
|
||||
</CacheProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
68
tsc1877/task1/aws/workspace/admin/src/pages/_document.js
Normal file
68
tsc1877/task1/aws/workspace/admin/src/pages/_document.js
Normal file
@@ -0,0 +1,68 @@
|
||||
// ** React Import
|
||||
import { Children } from 'react';
|
||||
|
||||
// ** Next Import
|
||||
import Document, { Html, Head, Main, NextScript } from 'next/document';
|
||||
|
||||
// ** Emotion Imports
|
||||
import createEmotionServer from '@emotion/server/create-instance';
|
||||
|
||||
// ** Utils Imports
|
||||
import { createEmotionCache } from 'src/@core/utils/create-emotion-cache';
|
||||
|
||||
class CustomDocument extends Document {
|
||||
render() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap"
|
||||
/>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png" />
|
||||
<link rel="shortcut icon" href="/images/favicon.png" />
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
CustomDocument.getInitialProps = async ctx => {
|
||||
const originalRenderPage = ctx.renderPage;
|
||||
const cache = createEmotionCache();
|
||||
const { extractCriticalToChunks } = createEmotionServer(cache);
|
||||
ctx.renderPage = () =>
|
||||
originalRenderPage({
|
||||
enhanceApp: App => props =>
|
||||
(
|
||||
<App
|
||||
{...props} // @ts-ignore
|
||||
emotionCache={cache}
|
||||
/>
|
||||
),
|
||||
});
|
||||
const initialProps = await Document.getInitialProps(ctx);
|
||||
const emotionStyles = extractCriticalToChunks(initialProps.html);
|
||||
|
||||
const emotionStyleTags = emotionStyles.styles.map(style => {
|
||||
return (
|
||||
<style
|
||||
key={style.key}
|
||||
dangerouslySetInnerHTML={{ __html: style.css }}
|
||||
data-emotion={`${style.key} ${style.ids.join(' ')}`}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
...initialProps,
|
||||
styles: [...Children.toArray(initialProps.styles), ...emotionStyleTags],
|
||||
};
|
||||
};
|
||||
|
||||
export default CustomDocument;
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user