feat: new templates

This commit is contained in:
Damien Ostler 2024-02-18 01:44:48 -05:00
parent 13bd42ecbd
commit 481bcd2d6c
147 changed files with 10517 additions and 310 deletions

View File

@ -146,7 +146,7 @@ function AppAppBar({ user }: AppAppBarProps) {
variant="contained"
size="small"
component="a"
href="/api/auth/login"
href="/dashboard"
startIcon={<OpenInNew />}
>
Dashboard

View File

@ -0,0 +1,53 @@
import * as React from 'react';
import { useEffect, useState } from "react";
import { Grid, Card, CardContent, Typography } from '@mui/material';
import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box';
const ArtistDashboardRequest = () => {
const [sellerRequestData, setSellerRequestData] = useState(null);
const getData = async () => {
const response = await fetch('/api/artist/request');
const sellerProfile = await response.json();
setSellerRequestData(sellerProfile);
}
useEffect(() => {
getData();
}, []);
let formattedTime = ""
if (sellerRequestData) {
const date = new Date(sellerRequestData["requestDate"]);
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
}
return (
(sellerRequestData ? (
<Card sx={{ minWidth: 275 }}>
<CardContent>
<Typography variant="h5" gutterBottom>
Request Status
</Typography>
{(sellerRequestData["accepted"] ? (
<Typography variant="body2" color="text.warning" component="div">Accepted</Typography>
) : (
<Typography variant="h6" color="text.warning" component="div">Pending</Typography>
))}
<Typography variant="body2" color="text.secondary" component="div">Request submitted on {formattedTime ?? ''}</Typography>
</CardContent>
</Card>) : (
<Box sx={{textAlign:"center", paddingTop:"5%"}}>
<Typography variant="h4" sx={{textAlign:"center"}}>
Loading
</Typography>
<Box sx={{ paddingTop: 5 }} />
<CircularProgress />
</Box>
))
)
}
export default ArtistDashboardRequest

View File

@ -3,7 +3,7 @@ import {ImageList, Box, Typography, CircularProgress} from '@mui/material';
import { useEffect, useState } from "react";
import ArtistPortfolioImage from './artistPortfolioImage';
const ArtistPortfolio = ({artistId}) => {
const ArtistPortfolio = ({masonry,columns,artistId}) => {
const [portfolioData, setPortfolioData] = useState([]);
const [loading, setLoading] = useState(true); // State for loading indicator
useEffect(() => {
@ -26,11 +26,19 @@ const ArtistPortfolio = ({artistId}) => {
</Box>
) :
(
<ImageList cols={2} rowHeight={200} sx={{maxHeight:400}}>
(masonry) ? (
<ImageList variant="masonry" gap={8} cols={columns} sx={{overflowY:"scroll", maxWidth:"100%"}} >
{portfolioData.map((item) => (
<ArtistPortfolioImage artistId={artistId} itemId={item.id} />
))}
</ImageList>
):(
<ImageList gap={8} cols={columns} >
{portfolioData.map((item) => (
<ArtistPortfolioImage artistId={artistId} itemId={item.id} />
))}
</ImageList>
)
)
)
}

View File

@ -14,7 +14,7 @@ const ArtistPortfolioImage = ({artistId,itemId}) => {
};
return (
<ImageListItem key={itemId }>
<ImageListItem key={itemId } >
<img
srcSet={process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${artistId}/Portfolio/${itemId}`}
src={process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${artistId}/Portfolio/${itemId}`}

View File

@ -4,7 +4,6 @@ import { useEffect, useState } from "react";
import EditableArtistPortfolioImage from './editableArtistPortfolioImage';
import FileOpenIcon from '@mui/icons-material/FileOpen';
import { Grid } from '@mui/material';
const EditableArtistPortfolio = ({ artistId }) => {
const [portfolioData, setPortfolioData] = useState([]);
const [loading, setLoading] = useState(true); // State for loading indicator

View File

@ -1,5 +1,5 @@
import Head from "next/head";
import Header from "./header";
import Header from "../header";
type LayoutProps = {
user?: any;

218
components/Onboarding.tsx Normal file
View File

@ -0,0 +1,218 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Stepper from '@mui/material/Stepper';
import Step from '@mui/material/Step';
import StepLabel from '@mui/material/StepLabel';
import StepContent from '@mui/material/StepContent';
import Button from '@mui/material/Button';
import Paper from '@mui/material/Paper';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Grid'
import TextField from '@mui/material/TextField';
import ArtistDashboardRequest from '../components/Old/artistDashboardRequest';
import ArtistPortfolio from '../components/Old/artistPortfolio';
import EditableArtistPortfolio from '../components/Old/editableArtistPortfolio';
import { useEffect, useState } from "react";
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
import {Card, CardContent, CardHeader, Divider } from '@mui/material';
const steps = [
{
label: 'Request Access As Artist',
description: `In order to start selling your art on our platform, you need to request access. Please include links to your social media and tag or DM us on the platform (@RequestDotBox). We may reach out for further verification and examples of your work.`,
},
{
label: 'Onboard On Stripe',
description:
'Our platform uses Stripe as a payment processor. You will be required to onboard with them with all of your payout information and business information.',
},
{
label: 'Setup Your Portfolio',
description: `This is where you can setup your initial portfolio. You can upload any image format file to your portfolio. It will be automatically displayed on your artist page. You can add and remove from this later.`,
},
];
export default function Onboarding() {
const [activeStep, setActiveStep] = React.useState(0);
const [sellerRequestData, setSellerRequestData] = React.useState(null);
const [profileData, setSellerProfileData] = React.useState(null);
const [isStripeOnboarded, setIsStripeOnboarded] = React.useState(false);
const [onBoardUrl, setOnBoardUrl] = React.useState("");
const handleNext = () => {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
const handleReset = () => {
setActiveStep(0);
};
const getData = async () => {
const onboardCheckRequest = await fetch('/api/artist/onboarded', { method: "GET" });
const onboardCheckResponse = await onboardCheckRequest.json();
setIsStripeOnboarded(onboardCheckResponse["onboarded"]);
const onboardUrlRequest = await fetch('/api/artist/onboardurl', { method: "GET" });
const onboardUrlResponse = await onboardUrlRequest.json();
setOnBoardUrl(onboardUrlResponse["onboardUrl"]);
const response = await fetch('/api/artist/request');
const sellerRequest = await response.json();
setSellerRequestData(sellerRequest);
const profileResponse = await fetch('/api/artist/profile');
const sellerProfile = await profileResponse.json();
setSellerProfileData(sellerProfile);
setTimeout(getData, 5000); // Poll every 5 seconds (adjust as needed)
}
React.useEffect(() => {
getData();
}, []);
const requestButton = () => {
fetch('/api/artist/newRequest').then((response) => {
if (response.ok) {
fetch('/api/artist/request').then((requestResponse) => {
requestResponse.json().then((sellerRequest) => {
setSellerRequestData(sellerRequest);
});
});
}
});
}
let formattedTime = ""
if (sellerRequestData) {
const date = new Date(sellerRequestData["requestDate"]);
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
}
return (
<Card sx={{ width:"100%", padding:"2%" }}>
<Stepper activeStep={activeStep} orientation="vertical">
{steps.map((step, index) => (
<Step key={step.label}>
<StepLabel
optional={
index === 2 ? (
<Typography variant="caption">Last step</Typography>
) : null
}
>
{step.label}
</StepLabel>
{(index==0) ? (
<StepContent>
<Grid container >
<Grid item xs={12} lg={12}>
<Typography>{step.description}</Typography>
</Grid>
{(sellerRequestData && Object.keys(sellerRequestData).length>0) ? (
<Grid item xs={12} lg={12} sx={{paddingTop:"2%"}}>
<ArtistDashboardRequest/>
</Grid>
):(
<Grid item xs={12} lg={12}>
<TextField fullWidth rows={4} multiline label="Application Message" variant="outlined" />
</Grid>
)}
</Grid>
<Box sx={{ mb: 2 ,paddingTop:"2%"}}>
<div>
{(sellerRequestData && Object.keys(sellerRequestData).length>0) ? (
(sellerRequestData["accepted"]) ? (
<Button variant="contained" onClick={handleNext}>
Continue
</Button>
) : (
<Button variant="contained" disabled>
Request Pending
</Button> )
):
(
<Button
variant="contained"
onClick={requestButton}
sx={{ mt: 1, mr: 1 }}
>
Request Access
</Button>
)}
</div>
</Box>
</StepContent>
): null}
{(index==1) ? (
<StepContent>
<Grid container>
<Grid item xs={12} lg={12}>
<Typography>{step.description}</Typography>
</Grid>
</Grid>
<Box sx={{ mb: 2 }}>
<div>
{isStripeOnboarded==true ? (
<Button
variant="contained"
onClick={handleNext}
sx={{ mt: 1, mr: 1 }}
>
Continue
</Button>
):(
<Button
color='success'
variant="contained"
href={onBoardUrl}
sx={{ mt: 1, mr: 1 }}
>
ONBOARD WITH STRIPE
</Button>
)}
</div>
</Box>
</StepContent>
): null}
{(index==2) ? (
<StepContent>
<Grid container>
<Grid item xs={12} lg={12}>
<Typography>{step.description}</Typography>
</Grid>
<Grid item xs={12} lg={12}>
<EditableArtistPortfolio artistId={profileData ? profileData["id"] : null}/>
</Grid>
</Grid>
<Box sx={{ mb: 2 }}>
<div>
<Button
variant="contained"
onClick={handleNext}
sx={{ mt: 1, mr: 1 }}
>
{index === steps.length - 1 ? 'Finish' : 'Continue'}
</Button>
</div>
</Box>
</StepContent>
): null}
</Step>
))}
</Stepper>
{activeStep === steps.length && (
<Paper square elevation={0} sx={{ p: 3 }}>
<Typography>We are setting up your account please wait.</Typography>
</Paper>
)}
</Card>
);
}

33
components/Orders.tsx Normal file
View File

@ -0,0 +1,33 @@
import * as React from 'react';
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid';
import { Button } from '@mui/material';
const columns: GridColDef[] = [
{ field: 'id', headerName: 'ID', width: 70 },
{ field: 'artist', headerName: 'Artist', width: 130 },
{ field: 'status', headerName: 'Status', width: 130 },
{ field: 'action', headerName: 'Action', width: 180, renderCell: (params) => {
return (<Button variant="outlined" color="primary" fullWidth>View More</Button>);
}},
];
const rows = [
{ id: 1, artist:'Neroshi', status: 'Pending'},
];
export default function Orders() {
return (
<div style={{ height: 400, width: '100%' }}>
<DataGrid
rows={rows}
columns={columns}
initialState={{
pagination: {
paginationModel: { page: 0, pageSize: 5 },
},
}}
pageSizeOptions={[5, 10]}
/>
</div>
);
}

View File

@ -1,67 +0,0 @@
import * as React from 'react';
import { useEffect, useState } from "react";
import { Grid, Card, CardContent, Typography } from '@mui/material';
import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box';
const ArtistDashboardRequest = () => {
const [sellerRequestData, setSellerRequestData] = useState(null);
const getData = async () => {
const response = await fetch('/api/artist/profile');
const sellerProfile = await response.json();
setSellerRequestData(sellerProfile);
}
useEffect(() => {
getData();
}, []);
let formattedTime = ""
if (sellerRequestData) {
const date = new Date(sellerRequestData["requestDate"]);
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
}
const requestButton = () => {
fetch('/api/artist/newRequest').then((response) => {
if (response.ok) {
fetch('/api/artist/request').then((requestResponse) => {
requestResponse.json().then((sellerRequest) => {
setSellerRequestData(sellerRequest);
getData();
});
});
}
});
}
return (
(sellerRequestData ? (
<Grid item xs={12} sm={12} lg={4} sx={{ textAlign: "center" ,paddingTop:"1rem"}}>
<Card sx={{ minWidth: 275 }}>
<CardContent>
<Typography variant="h5" gutterBottom>
Request Status
</Typography>
{(sellerRequestData["accepted"] ? (
<Typography variant="body2" color="text.warning" component="div">Accepted</Typography>
) : (
<Typography variant="h6" color="text.warning" component="div">Pending</Typography>
))}
<Typography variant="body2" color="text.secondary" component="div">Request submitted on {formattedTime ?? ''}</Typography>
</CardContent>
</Card>
</Grid>) : (
<Box sx={{textAlign:"center", paddingTop:"5%"}}>
<Typography variant="h4" sx={{textAlign:"center"}}>
Loading
</Typography>
<Box sx={{ paddingTop: 5 }} />
<CircularProgress />
</Box>
))
)
}
export default ArtistDashboardRequest

36
configs/themeConfig.tsx Normal file
View File

@ -0,0 +1,36 @@
// ** MUI Imports
import { PaletteMode } from '@mui/material'
// ** Types
import { ContentWidth } from '../core/layouts/types'
type ThemeConfig = {
mode: PaletteMode
templateName: string
routingLoader: boolean
disableRipple: boolean
navigationSize: number
menuTextTruncate: boolean
contentWidth: ContentWidth
responsiveFontSizes: boolean
}
const themeConfig: ThemeConfig = {
// ** Layout Configs
templateName: 'Request.Box' /* 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

View File

@ -0,0 +1,54 @@
// ** 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'
// ** Types Imports
import { CardStatsVerticalProps } from '../core/components/card-statistics/types'
const CardStatsVertical = (props: CardStatsVerticalProps) => {
// ** 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'
}

View File

@ -0,0 +1,15 @@
// ** React Imports
import { ReactNode } from 'react'
// ** Types
import { ThemeColor } from '../core/layouts/types'
export type CardStatsVerticalProps = {
title: string
stats: string
icon: ReactNode
subtitle: string
color?: ThemeColor
trendNumber: string
trend?: 'positive' | 'negative'
}

View 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

View File

@ -0,0 +1,47 @@
// ** React Imports
import { ReactNode } from 'react'
// ** MUI Imports
import Zoom from '@mui/material/Zoom'
import { styled } from '@mui/material/styles'
import useScrollTrigger from '@mui/material/useScrollTrigger'
interface ScrollToTopProps {
className?: string
children: ReactNode
}
const ScrollToTopStyled = styled('div')(({ theme }) => ({
zIndex: 11,
position: 'fixed',
right: theme.spacing(6),
bottom: theme.spacing(10)
}))
const ScrollToTop = (props: ScrollToTopProps) => {
// ** 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

View File

@ -0,0 +1,47 @@
// ** React Imports
import { createContext, useState, ReactNode } from 'react'
// ** MUI Imports
import { PaletteMode } from '@mui/material'
// ** ThemeConfig Import
import themeConfig from '../../configs/themeConfig'
// ** Types Import
import { ThemeColor, ContentWidth } from '../../core/layouts/types'
export type Settings = {
mode: PaletteMode
themeColor: ThemeColor
contentWidth: ContentWidth
}
export type SettingsContextValue = {
settings: Settings
saveSettings: (updatedSettings: Settings) => void
}
const initialSettings: Settings = {
themeColor: 'primary',
mode: themeConfig.mode,
contentWidth: themeConfig.contentWidth
}
// ** Create Context
export const SettingsContext = createContext<SettingsContextValue>({
saveSettings: () => null,
settings: initialSettings
})
export const SettingsProvider = ({ children }: { children: ReactNode }) => {
// ** State
const [settings, setSettings] = useState<Settings>({ ...initialSettings })
const saveSettings = (updatedSettings: Settings) => {
setSettings(updatedSettings)
}
return <SettingsContext.Provider value={{ settings, saveSettings }}>{children}</SettingsContext.Provider>
}
export const SettingsConsumer = SettingsContext.Consumer

View File

@ -0,0 +1,4 @@
import { useContext } from 'react'
import { SettingsContext, SettingsContextValue } from '../../core/context/settingsContext'
export const useSettings = (): SettingsContextValue => useContext(SettingsContext)

View File

@ -0,0 +1,40 @@
// ** MUI Imports
import { styled } from '@mui/material/styles'
import Box, { BoxProps } from '@mui/material/Box'
// ** Types
import { BlankLayoutProps } from './types'
// Styled component for Blank Layout component
const BlankLayoutWrapper = styled(Box)<BoxProps>(({ 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 }: BlankLayoutProps) => {
return (
<BlankLayoutWrapper className='layout-wrapper'>
<Box className='app-content' sx={{ minHeight: '100vh', overflowX: 'hidden', position: 'relative' }}>
{children}
</Box>
</BlankLayoutWrapper>
)
}
export default BlankLayout

View File

@ -0,0 +1,118 @@
// ** React Imports
import { useState } from 'react'
// ** MUI Imports
import Fab from '@mui/material/Fab'
import { styled } from '@mui/material/styles'
import Box, { BoxProps } from '@mui/material/Box'
// ** Icons Imports
import ArrowUp from 'mdi-material-ui/ArrowUp'
// ** Theme Config Import
import themeConfig from '../../configs/themeConfig'
// ** Type Import
import { LayoutProps } from '../../core/layouts/types'
// ** Components
import AppBar from './components/vertical/appBar'
import Navigation from './components/vertical/navigation'
import Footer from './components/shared-components/footer'
import ScrollToTop from '../../core/components/scroll-to-top'
// ** Styled Component
import DatePickerWrapper from '../../core/styles/libs/react-datepicker'
const VerticalLayoutWrapper = styled('div')({
height: '100%',
display: 'flex'
})
const MainContentWrapper = styled(Box)<BoxProps>({
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: LayoutProps) => {
// ** Props
const { settings, children, scrollToTop } = props
// ** Vars
const { contentWidth } = settings
const navWidth = themeConfig.navigationSize
// ** States
const [navVisible, setNavVisible] = useState<boolean>(false)
// ** Toggle Functions
const toggleNavVisibility = () => setNavVisible(!navVisible)
return (
<>
<VerticalLayoutWrapper className='layout-wrapper'>
{/* Navigation Menu */}
<Navigation
navWidth={navWidth}
navVisible={navVisible}
setNavVisible={setNavVisible}
toggleNavVisibility={toggleNavVisibility}
{...props}
/>
<MainContentWrapper className='layout-content-wrapper'>
{/* AppBar Component */}
<AppBar toggleNavVisibility={toggleNavVisibility} {...props} />
{/* Content */}
<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 Component */}
<Footer {...props} />
{/* Portal for React Datepicker */}
<DatePickerWrapper sx={{ zIndex: 11 }}>
<Box id='react-datepicker-portal'></Box>
</DatePickerWrapper>
</MainContentWrapper>
</VerticalLayoutWrapper>
{/* Scroll to top button */}
{scrollToTop ? (
scrollToTop(props)
) : (
<ScrollToTop className='mui-fixed'>
<Fab color='primary' size='small' aria-label='scroll back to top'>
<ArrowUp />
</Fab>
</ScrollToTop>
)}
</>
)
}
export default VerticalLayout

View File

@ -0,0 +1,40 @@
// ** MUI Imports
import { PaletteMode } from '@mui/material'
import IconButton from '@mui/material/IconButton'
// ** Icons Imports
import WeatherNight from 'mdi-material-ui/WeatherNight'
import WeatherSunny from 'mdi-material-ui/WeatherSunny'
// ** Type Import
import { Settings } from '../core/context/settingsContext'
interface Props {
settings: Settings
saveSettings: (values: Settings) => void
}
const ModeToggler = (props: Props) => {
// ** Props
const { settings, saveSettings } = props
const handleModeChange = (mode: PaletteMode) => {
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

View File

@ -0,0 +1,217 @@
// ** React Imports
import { useState, SyntheticEvent, Fragment, ReactNode } 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, Theme } from '@mui/material/styles'
import useMediaQuery from '@mui/material/useMediaQuery'
import MuiMenu, { MenuProps } from '@mui/material/Menu'
import MuiAvatar, { AvatarProps } from '@mui/material/Avatar'
import MuiMenuItem, { MenuItemProps } from '@mui/material/MenuItem'
import Typography, { TypographyProps } 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)<MenuProps>(({ 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)<MenuItemProps>(({ 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)<AvatarProps>({
width: '2.375rem',
height: '2.375rem',
fontSize: '1.125rem'
})
// ** Styled component for the title in MenuItems
const MenuItemTitle = styled(Typography)<TypographyProps>(({ 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)<TypographyProps>({
flex: '1 1 100%',
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis'
})
const NotificationDropdown = () => {
// ** States
const [anchorEl, setAnchorEl] = useState<(EventTarget & Element) | null>(null)
// ** Hook
const hidden = useMediaQuery((theme: Theme) => theme.breakpoints.down('lg'))
const handleDropdownOpen = (event: SyntheticEvent) => {
setAnchorEl(event.currentTarget)
}
const handleDropdownClose = () => {
setAnchorEl(null)
}
const ScrollWrapper = ({ children }: { children: ReactNode }) => {
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

View File

@ -0,0 +1,162 @@
// ** React Imports
import { useState, SyntheticEvent, 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'
import { useUser } from '@auth0/nextjs-auth0/client'
// ** 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 = () => {
const { user, isLoading } = useUser();
// ** States
const [anchorEl, setAnchorEl] = useState<Element | null>(null)
// ** Hooks
const router = useRouter()
const handleDropdownOpen = (event: SyntheticEvent) => {
setAnchorEl(event.currentTarget)
}
const handleDropdownClose = (url?: string) => {
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 (
(!isLoading && user) ? (
<Fragment>
<Badge
overlap='circular'
onClick={handleDropdownOpen}
sx={{ ml: 2, cursor: 'pointer' }}
badgeContent={<BadgeContentSpan />}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
>
<Avatar
alt={user.nickname}
onClick={handleDropdownOpen}
sx={{ width: 40, height: 40 }}
src={user.picture}
/>
</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={user.nickname} src={user.picture} sx={{ width: '2.5rem', height: '2.5rem' }} />
</Badge>
<Box sx={{ display: 'flex', marginLeft: 3, alignItems: 'flex-start', flexDirection: 'column' }}>
<Typography sx={{ fontWeight: 600 }}>{user.nickname}</Typography>
<Typography variant='body2' sx={{ fontSize: '0.8rem', color: 'text.disabled' }}>
Welcome back!
</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('/api/auth/logout')}>
<LogoutVariant sx={{ marginRight: 2, fontSize: '1.375rem', color: 'text.secondary' }} />
Logout
</MenuItem>
</Menu>
</Fragment>
): null
)
}
export default UserDropdown

View File

@ -0,0 +1,18 @@
// ** MUI Imports
import Box from '@mui/material/Box'
import Link from '@mui/material/Link'
import { Theme } from '@mui/material/styles'
import Typography from '@mui/material/Typography'
import useMediaQuery from '@mui/material/useMediaQuery'
const FooterContent = () => {
// ** Var
const hidden = useMediaQuery((theme: Theme) => theme.breakpoints.down('md'))
return (
<Box sx={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', justifyContent: 'space-between' }}>
</Box>
)
}
export default FooterContent

View File

@ -0,0 +1,57 @@
// ** React Imports
import { ReactNode } from 'react'
// ** MUI Imports
import Box from '@mui/material/Box'
import { useTheme } from '@mui/material/styles'
// ** Type Import
import { Settings } from '../core/context/settingsContext'
// ** Footer Content Component
import FooterContent from './FooterContent'
interface Props {
settings: Settings
saveSettings: (values: Settings) => void
footerContent?: (props?: any) => ReactNode
}
const Footer = (props: 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

View File

@ -0,0 +1,70 @@
// ** React Imports
import { ReactNode } from 'react'
// ** MUI Imports
import { styled, useTheme } from '@mui/material/styles'
import MuiAppBar, { AppBarProps } from '@mui/material/AppBar'
import MuiToolbar, { ToolbarProps } from '@mui/material/Toolbar'
// ** Type Import
import { Settings } from '../core/context/settingsContext'
interface Props {
hidden: boolean
settings: Settings
toggleNavVisibility: () => void
saveSettings: (values: Settings) => void
verticalAppBarContent?: (props?: any) => ReactNode
}
const AppBar = styled(MuiAppBar)<AppBarProps>(({ 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)<ToolbarProps>(({ 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) => {
// ** 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

View File

@ -0,0 +1,82 @@
// ** React Imports
import { ReactNode } from 'react'
// ** MUI Imports
import { styled, useTheme } from '@mui/material/styles'
import MuiSwipeableDrawer, { SwipeableDrawerProps } from '@mui/material/SwipeableDrawer'
// ** Type Import
import { Settings } from '../core/context/settingsContext'
interface Props {
hidden: boolean
navWidth: number
settings: Settings
navVisible: boolean
children: ReactNode
setNavVisible: (value: boolean) => void
saveSettings: (values: Settings) => void
}
const SwipeableDrawer = styled(MuiSwipeableDrawer)<SwipeableDrawerProps>({
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) => {
// ** 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

View File

@ -0,0 +1,75 @@
// ** React Import
import { ReactNode } from 'react'
// ** Next Import
import Link from 'next/link'
// ** MUI Imports
import Box, { BoxProps } from '@mui/material/Box'
import { styled, useTheme } from '@mui/material/styles'
import Typography, { TypographyProps } from '@mui/material/Typography'
// ** Type Import
import { Settings } from '../../../../../core/context/settingsContext'
// ** Configs
import themeConfig from '../../../../../configs/themeConfig'
interface Props {
hidden: boolean
settings: Settings
toggleNavVisibility: () => void
saveSettings: (values: Settings) => void
verticalNavMenuBranding?: (props?: any) => ReactNode
}
// ** Styled Components
const MenuHeaderWrapper = styled(Box)<BoxProps>(({ 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)<TypographyProps>(({ 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) => {
// ** Props
const { verticalNavMenuBranding: userVerticalNavMenuBranding } = props
// ** Hooks
const theme = useTheme()
return (
<MenuHeaderWrapper className='nav-header' sx={{ pl: 6 }}>
{userVerticalNavMenuBranding ? (
userVerticalNavMenuBranding(props)
) : (
<Link href='/' passHref>
<StyledLink>
<img width={30} height={25} src= "https://s6.imgcdn.dev/ttLwl.png"/>
<HeaderTitle variant='h6' sx={{ ml: 3 }}>
{themeConfig.templateName}
</HeaderTitle>
</StyledLink>
</Link>
)}
</MenuHeaderWrapper>
)
}
export default VerticalNavHeader

View File

@ -0,0 +1,39 @@
// ** Types Import
import { Settings } from '../core/context/settingsContext'
import { NavLink, NavSectionTitle, VerticalNavItemsType } from '../core/layouts/types'
// ** Custom Menu Components
import VerticalNavLink from './VerticalNavLink'
import VerticalNavSectionTitle from './VerticalNavSectionTitle'
interface Props {
settings: Settings
navVisible?: boolean
groupActive: string[]
currentActiveGroup: string[]
verticalNavItems?: VerticalNavItemsType
saveSettings: (values: Settings) => void
setGroupActive: (value: string[]) => void
setCurrentActiveGroup: (item: string[]) => void
}
const resolveNavItemComponent = (item: NavLink | NavSectionTitle) => {
if ((item as NavSectionTitle).sectionTitle) return VerticalNavSectionTitle
return VerticalNavLink
}
const VerticalNavItems = (props: Props) => {
// ** Props
const { verticalNavItems } = props
const RenderMenuItems = verticalNavItems?.map((item: NavLink | NavSectionTitle, index: number) => {
const TagName: any = resolveNavItemComponent(item)
return <TagName {...props} key={index} item={item} />
})
return <>{RenderMenuItems}</>
}
export default VerticalNavItems

View File

@ -0,0 +1,136 @@
// ** React Imports
import { ElementType, ReactNode } from 'react'
// ** 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, { BoxProps } from '@mui/material/Box'
import ListItemIcon from '@mui/material/ListItemIcon'
import ListItemButton, { ListItemButtonProps } from '@mui/material/ListItemButton'
// ** Configs Import
import themeConfig from '../../../../../configs/themeConfig'
// ** Types
import { NavLink } from '../../../../../core/layouts/types'
import { Settings } from '../../../../../core/context/settingsContext'
// ** Custom Components Imports
import UserIcon from '../../../../../layouts/components/UserIcon'
// ** Utils
import { handleURLQueries } from '../../../../../core/layouts/utils'
interface Props {
item: NavLink
settings: Settings
navVisible?: boolean
toggleNavVisibility: () => void
}
// ** Styled Components
const MenuNavLink = styled(ListItemButton)<
ListItemButtonProps & { component?: ElementType; target?: '_blank' | undefined }
>(({ 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)<BoxProps>({
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
transition: 'opacity .25s ease-in-out',
...(themeConfig.menuTextTruncate && { overflow: 'hidden' })
})
const VerticalNavLink = ({ item, navVisible, toggleNavVisibility }: Props) => {
// ** Hooks
const router = useRouter()
const IconTag: ReactNode = 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

View File

@ -0,0 +1,72 @@
// ** MUI Imports
import Divider from '@mui/material/Divider'
import { styled, useTheme } from '@mui/material/styles'
import Typography, { TypographyProps } from '@mui/material/Typography'
import MuiListSubheader, { ListSubheaderProps } from '@mui/material/ListSubheader'
// ** Types
import { NavSectionTitle } from '../core/layouts/types'
interface Props {
item: NavSectionTitle
}
// ** Styled Components
const ListSubheader = styled((props: ListSubheaderProps) => <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)<TypographyProps>(({ theme }) => ({
fontSize: '0.75rem',
lineHeight: 'normal',
letterSpacing: '0.21px',
textTransform: 'uppercase',
color: theme.palette.text.disabled,
fontWeight: theme.typography.fontWeightMedium
}))
const VerticalNavSectionTitle = (props: 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

View File

@ -0,0 +1,153 @@
// ** React Import
import { ReactNode, useRef, useState } from 'react'
// ** MUI Import
import List from '@mui/material/List'
import Box, { BoxProps } from '@mui/material/Box'
import { styled, useTheme } from '@mui/material/styles'
// ** Third Party Components
import PerfectScrollbar from 'react-perfect-scrollbar'
// ** Type Import
import { Settings } from '../../../../../core/context/settingsContext'
import { VerticalNavItemsType } from '../../../../../core/layouts/types'
// ** Component Imports
import Drawer from './Drawer'
import VerticalNavItems from './VerticalNavItems'
import VerticalNavHeader from './VerticalNavHeader'
// ** Util Import
import { hexToRGBA } from '../../../../../core/utils/hex-to-rgba'
interface Props {
hidden: boolean
navWidth: number
settings: Settings
children: ReactNode
navVisible: boolean
toggleNavVisibility: () => void
setNavVisible: (value: boolean) => void
verticalNavItems?: VerticalNavItemsType
saveSettings: (values: Settings) => void
verticalNavMenuContent?: (props?: any) => ReactNode
afterVerticalNavMenuContent?: (props?: any) => ReactNode
beforeVerticalNavMenuContent?: (props?: any) => ReactNode
}
const StyledBoxForShadow = styled(Box)<BoxProps>({
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) => {
// ** Props
const {
hidden,
afterVerticalNavMenuContent,
beforeVerticalNavMenuContent,
verticalNavMenuContent: userVerticalNavMenuContent
} = props
// ** States
const [groupActive, setGroupActive] = useState<string[]>([])
const [currentActiveGroup, setCurrentActiveGroup] = useState<string[]>([])
// ** Ref
const shadowRef = useRef(null)
// ** Hooks
const theme = useTheme()
// ** Fixes Navigation InfiniteScroll
const handleInfiniteScroll = (ref: HTMLElement) => {
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: any) => {
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' }}>
{/* @ts-ignore */}
<ScrollWrapper
{...(hidden
? {
onScroll: (container: any) => scrollMenu(container),
sx: { height: '100%', overflowY: 'auto', overflowX: 'hidden' }
}
: {
options: { wheelPropagation: false },
onScrollY: (container: any) => scrollMenu(container),
containerRef: (ref: any) => handleInfiniteScroll(ref)
})}
>
{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

46
core/layouts/types.ts Normal file
View File

@ -0,0 +1,46 @@
import { ReactNode } from 'react'
import { Settings } from '../core/context/settingsContext'
export type ContentWidth = 'full' | 'boxed'
export type ThemeColor = 'primary' | 'secondary' | 'error' | 'warning' | 'info' | 'success'
export type NavLink = {
path?: string
title: string
action?: string
subject?: string
disabled?: boolean
badgeContent?: string
externalLink?: boolean
openInNewTab?: boolean
icon?: string | string[] | ReactNode
badgeColor?: 'default' | 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info'
}
export type NavSectionTitle = {
sectionTitle: string
action?: string
subject?: string
}
export type VerticalNavItemsType = (NavLink | NavSectionTitle)[]
export type LayoutProps = {
hidden: boolean
settings: Settings
children: ReactNode
verticalNavItems?: VerticalNavItemsType
scrollToTop?: (props?: any) => ReactNode
saveSettings: (values: Settings) => void
footerContent?: (props?: any) => ReactNode
verticalAppBarContent?: (props?: any) => ReactNode
verticalNavMenuContent?: (props?: any) => ReactNode
verticalNavMenuBranding?: (props?: any) => ReactNode
afterVerticalNavMenuContent?: (props?: any) => ReactNode
beforeVerticalNavMenuContent?: (props?: any) => ReactNode
}
export type BlankLayoutProps = {
children: ReactNode
}

19
core/layouts/utils.ts Normal file
View File

@ -0,0 +1,19 @@
// ** Types
import { NextRouter } from 'next/router'
/**
* Check for URL queries as well for matching
* Current URL & Item Path
*
* @param item
* @param activeItem
*/
export const handleURLQueries = (router: NextRouter, path: string | undefined): boolean => {
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]] as string) && path !== '/'
}
return false
}

View 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

View File

@ -0,0 +1,361 @@
// ** MUI imports
import { styled } from '@mui/material/styles'
import Box, { BoxProps } from '@mui/material/Box'
// ** Util Import
import { hexToRGBA } from '../../../../core/utils/hex-to-rgba'
const DatePickerWrapper = styled(Box)<BoxProps>(({ 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

View File

@ -0,0 +1,60 @@
// ** React Imports
import { ReactNode } from 'react'
// ** MUI Imports
import CssBaseline from '@mui/material/CssBaseline'
import GlobalStyles from '@mui/material/GlobalStyles'
import { ThemeProvider, createTheme, responsiveFontSizes } from '@mui/material/styles'
// ** Type Imports
import { Settings } from '../../core/context/settingsContext'
// ** Theme Config
import themeConfig from '../../configs/themeConfig'
// ** Theme Override Imports
import overrides from './overrides'
import typography from './typography'
// ** Theme
import themeOptions from './ThemeOptions'
// ** Global Styles
import GlobalStyling from './globalStyles'
interface Props {
settings: Settings
children: ReactNode
}
const ThemeComponent = (props: 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) as any} />
{children}
</ThemeProvider>
)
}
export default ThemeComponent

View File

@ -0,0 +1,58 @@
// ** MUI Theme Provider
import { deepmerge } from '@mui/utils'
import { ThemeOptions } from '@mui/material'
// ** Type Import
import { Settings } from '../core/context/settingsContext'
// ** Theme Override Imports
import palette from './palette'
import spacing from './spacing'
import shadows from './shadows'
import breakpoints from './breakpoints'
const themeOptions = (settings: Settings): ThemeOptions => {
// ** 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

View File

@ -0,0 +1,11 @@
const breakpoints = () => ({
values: {
xs: 0,
sm: 600,
md: 900,
lg: 1200,
xl: 1536
}
})
export default breakpoints

View File

@ -0,0 +1,47 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const GlobalStyles = (theme: 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

View File

@ -0,0 +1,49 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Accordion = (theme: 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

View File

@ -0,0 +1,112 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
import { lighten, darken } from '@mui/material/styles'
// ** Util Import
import { hexToRGBA } from '../../../core/utils/hex-to-rgba'
const Alert = (theme: 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

View File

@ -0,0 +1,30 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Avatar = (theme: 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

View File

@ -0,0 +1,25 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
// ** Util Import
import { hexToRGBA } from '../../../core/utils/hex-to-rgba'
const Backdrop = (theme: 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

View File

@ -0,0 +1,53 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
// ** Theme Config Imports
import themeConfig from '../../../configs/themeConfig'
const Button = (theme: 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

View File

@ -0,0 +1,86 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Card = (theme: 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

View File

@ -0,0 +1,22 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Chip = (theme: Theme) => {
return {
MuiChip: {
styleOverrides: {
outlined: {
'&.MuiChip-colorDefault': {
borderColor: `rgba(${theme.palette.customColors.main}, 0.22)`
}
},
deleteIcon: {
width: 18,
height: 18
}
}
}
}
}
export default Chip

View File

@ -0,0 +1,64 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const DateTimePicker = (theme: 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

View File

@ -0,0 +1,107 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
// ** Util Import
import { hexToRGBA } from '../../../core/utils/hex-to-rgba'
const Dialog = (theme: 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

View File

@ -0,0 +1,16 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Divider = (theme: Theme) => {
return {
MuiDivider: {
styleOverrides: {
root: {
margin: `${theme.spacing(2)} 0`
}
}
}
}
}
export default Divider

View File

@ -0,0 +1,88 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
// ** 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: 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

View File

@ -0,0 +1,65 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const input = (theme: 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

View File

@ -0,0 +1,9 @@
export default {
MuiLink: {
styleOverrides: {
root: {
textDecoration: 'none'
}
}
}
}

View File

@ -0,0 +1,44 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const List = (theme: 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

View File

@ -0,0 +1,19 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Menu = (theme: Theme) => {
return {
MuiMenu: {
styleOverrides: {
root: {
'& .MuiMenu-paper': {
borderRadius: 5,
boxShadow: theme.palette.mode === 'light' ? theme.shadows[8] : theme.shadows[9]
}
}
}
}
}
}
export default Menu

View File

@ -0,0 +1,41 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
// ** Util Import
import { hexToRGBA } from '../../../core/utils/hex-to-rgba'
const Pagination = (theme: 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

View File

@ -0,0 +1,9 @@
export default {
MuiPaper: {
styleOverrides: {
root: {
backgroundImage: 'none'
}
}
}
}

View File

@ -0,0 +1,18 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Popover = (theme: Theme) => {
return {
MuiPopover: {
styleOverrides: {
root: {
'& .MuiPopover-paper': {
boxShadow: theme.shadows[6]
}
}
}
}
}
}
export default Popover

View File

@ -0,0 +1,16 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Rating = (theme: Theme) => {
return {
MuiRating: {
styleOverrides: {
root: {
color: theme.palette.warning.main
}
}
}
}
}
export default Rating

View File

@ -0,0 +1,12 @@
export default {
MuiSelect: {
styleOverrides: {
select: {
minWidth: '6rem !important',
'&.MuiTablePagination-select': {
minWidth: '1rem !important'
}
}
}
}
}

View File

@ -0,0 +1,16 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Snackbar = (theme: Theme) => {
return {
MuiSnackbarContent: {
styleOverrides: {
root: {
backgroundColor: theme.palette.mode === 'light' ? theme.palette.grey[900] : theme.palette.grey[100]
}
}
}
}
}
export default Snackbar

View File

@ -0,0 +1,18 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Switch = (theme: Theme) => {
return {
MuiSwitch: {
styleOverrides: {
root: {
'& .MuiSwitch-track': {
backgroundColor: `rgb(${theme.palette.customColors.main})`
}
}
}
}
}
}
export default Switch

View File

@ -0,0 +1,69 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Table = (theme: 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

View File

@ -0,0 +1,30 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Tabs = (theme: 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

View File

@ -0,0 +1,83 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
// ** Util Import
import { hexToRGBA } from '../../../core/utils/hex-to-rgba'
const Timeline = (theme: 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

View File

@ -0,0 +1,16 @@
export default {
MuiToggleButtonGroup: {
styleOverrides: {
root: {
borderRadius: 4
}
}
},
MuiToggleButton: {
styleOverrides: {
root: {
borderRadius: 4
}
}
}
}

View File

@ -0,0 +1,28 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
// ** Util Import
import { hexToRGBA } from '../../../core/utils/hex-to-rgba'
const Tooltip = (theme: 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

View File

@ -0,0 +1,16 @@
// ** MUI Imports
import { Theme } from '@mui/material/styles'
const Typography = (theme: Theme) => {
return {
MuiTypography: {
styleOverrides: {
gutterBottom: {
marginBottom: theme.spacing(2)
}
}
}
}
}
export default Typography

111
core/theme/palette/index.ts Normal file
View File

@ -0,0 +1,111 @@
// ** Type Imports
import { PaletteMode } from '@mui/material'
import { ThemeColor } from '../core/layouts/types'
const DefaultPalette = (mode: PaletteMode, themeColor: ThemeColor) => {
// ** Vars
const lightColor = '58, 53, 65'
const darkColor = '231, 227, 252'
const mainColor = mode === 'light' ? lightColor : darkColor
const primaryGradient = () => {
if (themeColor === 'primary') {
return '#C6A7FE'
} 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: '#9E69FD',
main: '#9155FD',
dark: '#804BDF',
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

View File

@ -0,0 +1,63 @@
// ** Theme Type Import
import { PaletteMode, ThemeOptions } from '@mui/material'
const Shadows = (mode: PaletteMode): ThemeOptions['shadows'] => {
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

View File

@ -0,0 +1,3 @@
export default {
spacing: (factor: number) => `${0.25 * factor}rem`
}

18
core/theme/types.ts Normal file
View File

@ -0,0 +1,18 @@
declare module '@mui/material/styles' {
interface Palette {
customColors: {
main: string
tableHeaderBg: string
primaryGradient: string
}
}
interface PaletteOptions {
customColors?: {
main?: string
tableHeaderBg?: string
primaryGradient?: string
}
}
}
export {}

View File

@ -0,0 +1,67 @@
// ** Theme Type Import
import { Theme } from '@mui/material/styles'
const Typography = (theme: 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

View File

@ -0,0 +1,5 @@
import createCache from '@emotion/cache'
export const createEmotionCache = () => {
return createCache({ key: 'css' })
}

16
core/utils/hex-to-rgba.ts Normal file
View File

@ -0,0 +1,16 @@
/**
** Hex color to RGBA color
*/
export const hexToRGBA = (hexCode: string, opacity: number) => {
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})`
}

77
layouts/UserLayout.tsx Normal file
View File

@ -0,0 +1,77 @@
// ** React Imports
import { ReactNode } from 'react'
// ** MUI Imports
import Box from '@mui/material/Box'
import { Theme } from '@mui/material/styles'
import useMediaQuery from '@mui/material/useMediaQuery'
// ** Layout Imports
// !Do not remove this Layout import
import VerticalLayout from '../core/layouts/VerticalLayout'
// ** Navigation Imports
import VerticalNavItems from '../navigation/vertical'
// ** Component Import
import UpgradeToProButton from './components/UpgradeToProButton'
import VerticalAppBarContent from './components/vertical/AppBarContent'
// ** Hook Import
import { useSettings } from '../core/hooks/useSettings'
interface Props {
children: ReactNode
}
const UserLayout = ({ children }: Props) => {
// ** 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) => 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}
</VerticalLayout>
)
}
export default UserLayout

View File

@ -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<boolean>(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: any) => 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

View File

@ -0,0 +1,29 @@
// ** React Imports
import { ReactNode } from 'react'
// ** MUI Imports
import { SvgIconProps } from '@mui/material'
interface UserIconProps {
iconProps?: SvgIconProps
icon: string | ReactNode
}
const UserIcon = (props: UserIconProps) => {
// ** 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

View File

@ -0,0 +1,79 @@
// ** MUI Imports
import Box from '@mui/material/Box'
import { Theme } from '@mui/material/styles'
import TextField from '@mui/material/TextField'
import IconButton from '@mui/material/IconButton'
import useMediaQuery from '@mui/material/useMediaQuery'
import InputAdornment from '@mui/material/InputAdornment'
import {
NovuProvider,
PopoverNotificationCenter,
NotificationBell,
} from '@novu/notification-center';
// ** Icons Imports
import Menu from 'mdi-material-ui/Menu'
import Magnify from 'mdi-material-ui/Magnify'
// ** Type Import
import { Settings } from '../../../core/context/settingsContext'
// ** Components
import ModeToggler from '../../../core/layouts/components/shared-components/ModeToggler'
import UserDropdown from '../../../core/layouts/components/shared-components/UserDropdown'
import NotificationDropdown from '../../../core/layouts/components/shared-components/NotificationDropdown'
interface Props {
hidden: boolean
settings: Settings
toggleNavVisibility: () => void
saveSettings: (values: Settings) => void
}
const AppBarContent = (props: Props) => {
// ** Props
const { hidden, settings, saveSettings, toggleNavVisibility } = props
// ** Hook
const hiddenSm = useMediaQuery((theme: 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}
<TextField
size='small'
sx={{ '& .MuiOutlinedInput-root': { borderRadius: 4 } }}
InputProps={{
startAdornment: (
<InputAdornment position='start'>
<Magnify fontSize='small' />
</InputAdornment>
)
}}
/>
</Box>
<Box className='actions-right' sx={{ display: 'flex', alignItems: 'center' }}>
<ModeToggler settings={settings} saveSettings={saveSettings} />
<NovuProvider subscriberId={'on-boarding-subscriber-id-123'} applicationIdentifier={'9SKjzgN_odAF'}>
<PopoverNotificationCenter colorScheme={'light'}>
{({ unseenCount }) => <NotificationBell unseenCount={unseenCount} />}
</PopoverNotificationCenter>
</NovuProvider>
<UserDropdown />
</Box>
</Box>
)
}
export default AppBarContent

View File

@ -0,0 +1,82 @@
// ** 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'
// ** Type import
import { VerticalNavItemsType } from '../../core/layouts/types'
import { BankTransfer, PageFirst } from 'mdi-material-ui'
import { DocumentScanner, FileOpen, Settings } from '@mui/icons-material'
import { useState, useEffect } from 'react'
const navigation = (): VerticalNavItemsType => {
const [isStripeOnboarded, setIsStripeOnboarded] = useState(false);
const getData = async () => {
const onboardCheckRequest = await fetch('/api/artist/onboarded', { method: "GET" });
const onboardCheckResponse = await onboardCheckRequest.json();
setIsStripeOnboarded(onboardCheckResponse["onboarded"]);
}
useEffect(() => {
getData();
}, []);
if(isStripeOnboarded){
return [
{
sectionTitle: 'General'
},
{
title: 'Dashboard',
icon: HomeOutline,
path: '/dashboard'
},
{
title: 'Account Settings',
icon: Settings,
path: '/artist/settings'
},
{
sectionTitle: 'Artist'
},
{
title: 'Payout Portal',
icon: BankTransfer,
path: '/payoutportal'
},
{
title: 'Page Settings',
icon: DocumentScanner,
path: '/dashboard/artist/pagesettings'
},
{
title: 'Preview Page',
icon: FileOpen,
path: '/artist/pagesettings'
}
]
}
else{
return [
{
sectionTitle: 'General'
},
{
title: 'Dashboard',
icon: HomeOutline,
path: '/dashboard'
}
]
}
}
export default navigation

432
package-lock.json generated
View File

@ -7,6 +7,7 @@
"dependencies": {
"@auth0/nextjs-auth0": "^2.2.0",
"@emotion/react": "^11.11.3",
"@emotion/server": "^11.11.0",
"@emotion/styled": "^11.11.0",
"@fontsource/roboto": "^5.0.8",
"@lupus-ai/mui-currency-textfield": "^1.0.3",
@ -16,12 +17,20 @@
"@mui/x-data-grid": "^6.19.4",
"@mui/x-date-pickers": "^6.19.4",
"@novu/notification-center": "^0.22.0",
"apexcharts": "^3.45.2",
"dayjs": "^1.11.10",
"formidable": "^3.5.1",
"mdi-material-ui": "^7.8.0",
"mui-color-input": "^2.0.2",
"next": "latest",
"nprogress": "^0.2.0",
"openapi-typescript-fetch": "^1.1.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-apexcharts": "^1.4.1",
"react-datepicker": "^6.1.0",
"react-dom": "^18.2.0",
"react-perfect-scrollbar": "^1.5.8",
"react-popper": "^2.3.0"
},
"devDependencies": {
"@types/node": "^18.0.0",
@ -128,6 +137,14 @@
"node": ">=6.9.0"
}
},
"node_modules/@ctrl/tinycolor": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.0.3.tgz",
"integrity": "sha512-e9nEVehVJwkymQpkGhdSNzLT2Lr9UTTby+JePq4Z2SxBbOQjY7pLgSouAaXvfaGQVSAaY0U4eJdwfSDmCbItcw==",
"engines": {
"node": ">=14"
}
},
"node_modules/@emotion/babel-plugin": {
"version": "11.11.0",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz",
@ -223,6 +240,25 @@
"csstype": "^3.0.2"
}
},
"node_modules/@emotion/server": {
"version": "11.11.0",
"resolved": "https://registry.npmjs.org/@emotion/server/-/server-11.11.0.tgz",
"integrity": "sha512-6q89fj2z8VBTx9w93kJ5n51hsmtYuFPtZgnc1L8VzRx9ti4EU6EyvF6Nn1H1x3vcCQCF7u2dB2lY4AYJwUW4PA==",
"dependencies": {
"@emotion/utils": "^1.2.1",
"html-tokenize": "^2.0.0",
"multipipe": "^1.0.2",
"through": "^2.3.8"
},
"peerDependencies": {
"@emotion/css": "^11.0.0-rc.0"
},
"peerDependenciesMeta": {
"@emotion/css": {
"optional": true
}
}
},
"node_modules/@emotion/sheet": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz",
@ -1290,6 +1326,11 @@
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.8.tgz",
"integrity": "sha512-c/hzNDBh7eRF+KbCf+OoZxKbnkpaK/cKp9iLQWqB7muXtM+MtL9SUUH8vCFcLn6dH1Qm05jiexK0ofWY7TfOhQ=="
},
"node_modules/@yr/monotone-cubic-spline": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz",
"integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA=="
},
"node_modules/acorn": {
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
@ -1321,6 +1362,20 @@
"node": ">=4"
}
},
"node_modules/apexcharts": {
"version": "3.45.2",
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.45.2.tgz",
"integrity": "sha512-PpuM4sJWy70sUh5U1IFn1m1p45MdHSChLUNnqEoUUUHSU2IHZugFrsVNhov1S8Q0cvfdrCRCvdBtHGSs6PSAWQ==",
"dependencies": {
"@yr/monotone-cubic-spline": "^1.0.3",
"svg.draggable.js": "^2.2.2",
"svg.easing.js": "^2.0.0",
"svg.filter.js": "^2.0.2",
"svg.pathmorphing.js": "^0.1.3",
"svg.resize.js": "^1.4.3",
"svg.select.js": "^3.0.1"
}
},
"node_modules/aria-hidden": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz",
@ -1375,6 +1430,11 @@
"npm": ">=6"
}
},
"node_modules/buffer-from": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz",
"integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg=="
},
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
@ -1449,6 +1509,11 @@
"validator": "^13.7.0"
}
},
"node_modules/classnames": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
},
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
@ -1499,6 +1564,11 @@
"node": ">= 0.6"
}
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@ -1519,6 +1589,15 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/date-fns": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.3.1.tgz",
"integrity": "sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/dayjs": {
"version": "1.11.10",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz",
@ -1574,6 +1653,41 @@
"csstype": "^3.0.2"
}
},
"node_modules/duplexer2": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
"integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
"dependencies": {
"readable-stream": "^2.0.2"
}
},
"node_modules/duplexer2/node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
},
"node_modules/duplexer2/node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/duplexer2/node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/engine.io-client": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
@ -1716,6 +1830,21 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/html-tokenize": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-2.0.1.tgz",
"integrity": "sha512-QY6S+hZ0f5m1WT8WffYN+Hg+xm/w5I8XeUcAq/ZYP5wVC8xbKi4Whhru3FtrAebD5EhBW8rmFzkDI6eCAuFe2w==",
"dependencies": {
"buffer-from": "~0.1.1",
"inherits": "~2.0.1",
"minimist": "~1.2.5",
"readable-stream": "~1.0.27-1",
"through2": "~0.4.1"
},
"bin": {
"html-tokenize": "bin/cmd.js"
}
},
"node_modules/http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
@ -1767,6 +1896,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
},
"node_modules/joi": {
"version": "17.12.1",
"resolved": "https://registry.npmjs.org/joi/-/joi-17.12.1.tgz",
@ -1844,6 +1978,15 @@
"node": ">=10"
}
},
"node_modules/mdi-material-ui": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/mdi-material-ui/-/mdi-material-ui-7.8.0.tgz",
"integrity": "sha512-jLZKGDZ94Mav4c3r8Cyehqs1dHOviXuIm7vGGCIyxIf4UsWNiveQTCoCrKG2K63IWCHcMg0EfjLFqh4LGaYvoQ==",
"peerDependencies": {
"@mui/material": "^5.0.0 || ^5.0.0-rc.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@ -1863,11 +2006,49 @@
"node": ">= 0.6"
}
},
"node_modules/minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/mui-color-input": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/mui-color-input/-/mui-color-input-2.0.2.tgz",
"integrity": "sha512-jDwoX7j8C6Q10Kr1fRB2HCqm4VS1Q97PZnPd/2sIH3R9B+yNzhyCYFQsJj/CdV1jte2UudUOopLiJkeBZCK5WQ==",
"dependencies": {
"@ctrl/tinycolor": "^4.0.3"
},
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@mui/material": "^5.0.0",
"@types/react": "^18.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/multipipe": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/multipipe/-/multipipe-1.0.2.tgz",
"integrity": "sha512-6uiC9OvY71vzSGX8lZvSqscE7ft9nPupJ8fMjrCNRAUy2LREUW42UL+V/NTrogr6rFgRydUrCX4ZitfpSNkSCQ==",
"dependencies": {
"duplexer2": "^0.1.2",
"object-assign": "^4.1.0"
}
},
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
@ -1930,6 +2111,11 @@
}
}
},
"node_modules/nprogress": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
"integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA=="
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@ -1946,6 +2132,11 @@
"node": ">= 6"
}
},
"node_modules/object-keys": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
"integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw=="
},
"node_modules/oidc-token-hash": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz",
@ -2026,6 +2217,11 @@
"node": ">=8"
}
},
"node_modules/perfect-scrollbar": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.5.tgz",
"integrity": "sha512-dzalfutyP3e/FOpdlhVryN4AJ5XDVauVWxybSkLZmakFE2sS3y3pc4JnSprw8tGmHvkaG5Edr5T7LBTZ+WWU2g=="
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@ -2058,6 +2254,11 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@ -2089,6 +2290,48 @@
"node": ">=0.10.0"
}
},
"node_modules/react-apexcharts": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/react-apexcharts/-/react-apexcharts-1.4.1.tgz",
"integrity": "sha512-G14nVaD64Bnbgy8tYxkjuXEUp/7h30Q0U33xc3AwtGFijJB9nHqOt1a6eG0WBn055RgRg+NwqbKGtqPxy15d0Q==",
"dependencies": {
"prop-types": "^15.8.1"
},
"peerDependencies": {
"apexcharts": "^3.41.0",
"react": ">=0.13"
}
},
"node_modules/react-datepicker": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-6.1.0.tgz",
"integrity": "sha512-8uz+hAOpvHqZGvD4Ky1hJ0/tLI4S9B0Gu9LV7LtLxRKXODs/xrxEay0aMVp7AW9iizTeImZh/6aA00fFaRZpJw==",
"dependencies": {
"@floating-ui/react": "^0.26.2",
"classnames": "^2.2.6",
"date-fns": "^3.3.1",
"prop-types": "^15.7.2",
"react-onclickoutside": "^6.13.0"
},
"peerDependencies": {
"react": "^16.9.0 || ^17 || ^18",
"react-dom": "^16.9.0 || ^17 || ^18"
}
},
"node_modules/react-datepicker/node_modules/@floating-ui/react": {
"version": "0.26.9",
"resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.9.tgz",
"integrity": "sha512-p86wynZJVEkEq2BBjY/8p2g3biQ6TlgT4o/3KgFKyTWoJLU1GZ8wpctwRqtkEl2tseYA+kw7dBAIDFcednfI5w==",
"dependencies": {
"@floating-ui/react-dom": "^2.0.8",
"@floating-ui/utils": "^0.2.1",
"tabbable": "^6.0.1"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
@ -2101,6 +2344,11 @@
"react": "^18.2.0"
}
},
"node_modules/react-fast-compare": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
},
"node_modules/react-infinite-scroll-component": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz",
@ -2117,6 +2365,46 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/react-onclickoutside": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz",
"integrity": "sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==",
"funding": {
"type": "individual",
"url": "https://github.com/Pomax/react-onclickoutside/blob/master/FUNDING.md"
},
"peerDependencies": {
"react": "^15.5.x || ^16.x || ^17.x || ^18.x",
"react-dom": "^15.5.x || ^16.x || ^17.x || ^18.x"
}
},
"node_modules/react-perfect-scrollbar": {
"version": "1.5.8",
"resolved": "https://registry.npmjs.org/react-perfect-scrollbar/-/react-perfect-scrollbar-1.5.8.tgz",
"integrity": "sha512-bQ46m70gp/HJtiBOF3gRzBISSZn8FFGNxznTdmTG8AAwpxG1bJCyn7shrgjEvGSQ5FJEafVEiosY+ccER11OSA==",
"dependencies": {
"perfect-scrollbar": "^1.5.0",
"prop-types": "^15.6.1"
},
"peerDependencies": {
"react": ">=16.3.3",
"react-dom": ">=16.3.3"
}
},
"node_modules/react-popper": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
"integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==",
"dependencies": {
"react-fast-compare": "^3.0.1",
"warning": "^4.0.2"
},
"peerDependencies": {
"@popperjs/core": "^2.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
}
},
"node_modules/react-textarea-autosize": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.4.tgz",
@ -2148,6 +2436,17 @@
"react-dom": ">=16.6.0"
}
},
"node_modules/readable-stream": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
@ -2182,6 +2481,11 @@
"node": ">=4"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
@ -2253,6 +2557,11 @@
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
},
"node_modules/styled-jsx": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
@ -2302,6 +2611,89 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/svg.draggable.js": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
"dependencies": {
"svg.js": "^2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.easing.js": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
"integrity": "sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==",
"dependencies": {
"svg.js": ">=2.3.x"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.filter.js": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
"integrity": "sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==",
"dependencies": {
"svg.js": "^2.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.js": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="
},
"node_modules/svg.pathmorphing.js": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
"dependencies": {
"svg.js": "^2.4.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.resize.js": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
"dependencies": {
"svg.js": "^2.6.5",
"svg.select.js": "^2.1.2"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.resize.js/node_modules/svg.select.js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
"dependencies": {
"svg.js": "^2.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.select.js": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
"dependencies": {
"svg.js": "^2.6.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/tabbable": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
@ -2315,6 +2707,20 @@
"node": ">=8"
}
},
"node_modules/through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
},
"node_modules/through2": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz",
"integrity": "sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==",
"dependencies": {
"readable-stream": "~1.0.17",
"xtend": "~2.1.1"
}
},
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@ -2429,6 +2835,11 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/validator": {
"version": "13.11.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
@ -2437,6 +2848,14 @@
"node": ">= 0.10"
}
},
"node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/webfontloader": {
"version": "1.6.28",
"resolved": "https://registry.npmjs.org/webfontloader/-/webfontloader-1.6.28.tgz",
@ -2475,6 +2894,17 @@
"node": ">=0.4.0"
}
},
"node_modules/xtend": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
"integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==",
"dependencies": {
"object-keys": "~0.4.0"
},
"engines": {
"node": ">=0.4"
}
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",

View File

@ -8,6 +8,7 @@
"dependencies": {
"@auth0/nextjs-auth0": "^2.2.0",
"@emotion/react": "^11.11.3",
"@emotion/server": "^11.11.0",
"@emotion/styled": "^11.11.0",
"@fontsource/roboto": "^5.0.8",
"@lupus-ai/mui-currency-textfield": "^1.0.3",
@ -17,12 +18,20 @@
"@mui/x-data-grid": "^6.19.4",
"@mui/x-date-pickers": "^6.19.4",
"@novu/notification-center": "^0.22.0",
"apexcharts": "^3.45.2",
"dayjs": "^1.11.10",
"formidable": "^3.5.1",
"mdi-material-ui": "^7.8.0",
"mui-color-input": "^2.0.2",
"next": "latest",
"nprogress": "^0.2.0",
"openapi-typescript-fetch": "^1.1.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-apexcharts": "^1.4.1",
"react-datepicker": "^6.1.0",
"react-dom": "^18.2.0",
"react-perfect-scrollbar": "^1.5.8",
"react-popper": "^2.3.0"
},
"devDependencies": {
"@types/node": "^18.0.0",

65
pages/401.tsx Normal file
View File

@ -0,0 +1,65 @@
// ** React Imports
import { ReactNode } from 'react'
// ** 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, { BoxProps } from '@mui/material/Box'
// ** Layout Import
import BlankLayout from '../core/layouts/BlankLayout'
// ** Demo Imports
import FooterIllustrations from '../views/pages/misc/FooterIllustrations'
// ** Styled Components
const BoxWrapper = styled(Box)<BoxProps>(({ 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&prime;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: ReactNode) => <BlankLayout>{page}</BlankLayout>
export default Error401

74
pages/404.tsx Normal file
View File

@ -0,0 +1,74 @@
// ** React Imports
import { ReactNode } from 'react'
// ** 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, { BoxProps } from '@mui/material/Box'
// ** Layout Import
import BlankLayout from '../core/layouts/BlankLayout'
// ** Demo Imports
import FooterIllustrations from '../views/pages/misc/FooterIllustrations'
// ** Styled Components
const BoxWrapper = styled(Box)<BoxProps>(({ 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&prime;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 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: ReactNode) => <BlankLayout>{page}</BlankLayout>
export default Error404

74
pages/500.tsx Normal file
View File

@ -0,0 +1,74 @@
// ** React Imports
import { ReactNode } from 'react'
// ** 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, { BoxProps } from '@mui/material/Box'
// ** Layout Import
import BlankLayout from '../core/layouts/BlankLayout'
// ** Demo Imports
import FooterIllustrations from '../views/pages/misc/FooterIllustrations'
// ** Styled Components
const BoxWrapper = styled(Box)<BoxProps>(({ 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: ReactNode) => <BlankLayout>{page}</BlankLayout>
export default Error500

View File

@ -1,38 +1,104 @@
// ** Next Imports
import Head from 'next/head'
import { Router } from 'next/router'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
// ** Loader Import
import NProgress from 'nprogress'
import { UserProvider } from "@auth0/nextjs-auth0/client";
import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';
import { createTheme } from '@mui/material/styles';
import { green, purple } from '@mui/material/colors';
import { ThemeProvider } from "@emotion/react";
// ** Emotion Imports
import { CacheProvider } from '@emotion/react'
import type { EmotionCache } from '@emotion/cache'
const theme = createTheme({
palette: {
primary: {
main: '#1D3555',
},
secondary: {
main: '#E5BEED'
},
background: {
default: '#3D3E46',
paper: '#FAFAFF'
}
},
})
// ** Config Imports
import themeConfig from '../configs/themeConfig'
// ** Component Imports
import UserLayout from '../layouts/UserLayout'
import ThemeComponent from '../core/theme/ThemeComponent'
// ** Contexts
import { SettingsConsumer, SettingsProvider } from '../core/context/settingsContext'
// ** Utils Imports
import { createEmotionCache } from '../core/utils/create-emotion-cache'
import { useEffect, useState } from 'react'
import { useRouter } from 'next/router';
// ** React Perfect Scrollbar Style
import 'react-perfect-scrollbar/dist/css/styles.css'
// ** Global css styles
import '../styles/globals.css'
// ** Extend App Props with Emotion
type ExtendedAppProps = AppProps & {
Component: NextPage
emotionCache: EmotionCache
}
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()
})
}
export default function App({ Component, pageProps }) {
// optionally pass the 'user' prop from pages that require server-side
// rendering to prepopulate the 'useUser' hook.
// ** Configure JSS & ClassName
const App = (props: ExtendedAppProps) => {
const { Component, emotionCache = clientSideEmotionCache, pageProps } = props
const { user } = pageProps;
// Variables
const getLayout = Component.getLayout ?? (page => <UserLayout>{page}</UserLayout>)
const [isRootPath, setIsRootPath] = useState<boolean>(true);
const router = useRouter();
useEffect(() => {
setIsRootPath(router.pathname === '/');
}, [router.pathname]);
return (
<UserProvider user={user}>
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
<UserProvider user={user}>
<CacheProvider value={emotionCache}>
<Head>
<title>{`Request.Box`}</title>
<meta
name='description'
content={`Request.Box is a platform for artists to allow their followered to request art pieces while allowing the artist complete control of the terms and timeframe.`}
/>
<meta name='keywords' content='Art, Commission, Skeb, Artwork, Freelance, Illustration, Vtuber, Vtubing, Vtuber Rigging, Illustration' />
<meta name='viewport' content='initial-scale=1, width=device-width' />
</Head>
<SettingsProvider>
<SettingsConsumer>
{({ settings }) => {{
if (isRootPath) {
return <ThemeComponent settings={settings}><Component {...pageProps} /> </ThemeComponent>
} else {
return <ThemeComponent settings={settings}>{getLayout(<Component {...pageProps} />)}</ThemeComponent>;
}
}}}
</SettingsConsumer>
</SettingsProvider>
</CacheProvider>
</UserProvider>
);
)
}
export default App

70
pages/_document.tsx Normal file
View File

@ -0,0 +1,70 @@
// ** 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 '../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

View File

@ -0,0 +1,103 @@
// ** React Imports
import { SyntheticEvent, useState } from 'react'
// ** MUI Imports
import Box from '@mui/material/Box'
import Card from '@mui/material/Card'
import TabList from '@mui/lab/TabList'
import TabPanel from '@mui/lab/TabPanel'
import TabContext from '@mui/lab/TabContext'
import { styled } from '@mui/material/styles'
import MuiTab, { TabProps } from '@mui/material/Tab'
// ** Icons Imports
import AccountOutline from 'mdi-material-ui/AccountOutline'
import LockOpenOutline from 'mdi-material-ui/LockOpenOutline'
import InformationOutline from 'mdi-material-ui/InformationOutline'
// ** Demo Tabs Imports
import TabInfo from '../../views/account-settings/TabInfo'
import TabAccount from '../../views/account-settings/TabAccount'
import TabSecurity from '../../views/account-settings/TabSecurity'
// ** Third Party Styles Imports
import 'react-datepicker/dist/react-datepicker.css'
const Tab = styled(MuiTab)<TabProps>(({ theme }) => ({
[theme.breakpoints.down('md')]: {
minWidth: 100
},
[theme.breakpoints.down('sm')]: {
minWidth: 67
}
}))
const TabName = styled('span')(({ theme }) => ({
lineHeight: 1.71,
fontSize: '0.875rem',
marginLeft: theme.spacing(2.4),
[theme.breakpoints.down('md')]: {
display: 'none'
}
}))
const AccountSettings = () => {
// ** State
const [value, setValue] = useState<string>('account')
const handleChange = (event: SyntheticEvent, newValue: string) => {
setValue(newValue)
}
return (
<Card>
<TabContext value={value}>
<TabList
onChange={handleChange}
aria-label='account-settings tabs'
sx={{ borderBottom: theme => `1px solid ${theme.palette.divider}` }}
>
<Tab
value='account'
label={
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<AccountOutline />
<TabName>Account</TabName>
</Box>
}
/>
<Tab
value='security'
label={
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<LockOpenOutline />
<TabName>Security</TabName>
</Box>
}
/>
<Tab
value='info'
label={
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<InformationOutline />
<TabName>Info</TabName>
</Box>
}
/>
</TabList>
<TabPanel sx={{ p: 0 }} value='account'>
<TabAccount />
</TabPanel>
<TabPanel sx={{ p: 0 }} value='security'>
<TabSecurity />
</TabPanel>
<TabPanel sx={{ p: 0 }} value='info'>
<TabInfo />
</TabPanel>
</TabContext>
</Card>
)
}
export default AccountSettings

View File

@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
import { useUser } from "@auth0/nextjs-auth0/client";
import Layout from "../../components/layout";
import Layout from "../../components/OLd/layout";
const ApiProfile = () => {
const { user, isLoading } = useUser();

View File

@ -1,5 +1,5 @@
import { withPageAuthRequired } from "@auth0/nextjs-auth0";
import Layout from "../../components/layout";
import Layout from "../../components/OLd/layout";
import { User } from "../../interfaces";
type ProfileProps = {

View File

@ -1,4 +1,4 @@
import Layout from "../../components/layout";
import Layout from "../../components/OLd/layout";
import { useUser } from "@auth0/nextjs-auth0/client";
import { Box, Grid, Card, CardContent, Typography, List, Button, CircularProgress, Tooltip } from "@mui/material";
import { useState, useEffect } from "react";

View File

@ -1,4 +1,4 @@
import Layout from "../../../components/layout";
import Layout from "../../../components/OLd/layout";
import { useUser } from "@auth0/nextjs-auth0/client";
import { Box, Grid, Typography, Button, CircularProgress, TextField} from "@mui/material";
import { useState, useEffect } from "react";

View File

@ -1,201 +0,0 @@
import { useUser } from "@auth0/nextjs-auth0/client";
import { useTheme } from '@mui/material/styles';
import AppBar from '@mui/material/AppBar';
import Tabs from '@mui/material/Tabs';
import Tab from '@mui/material/Tab';
import { Grid, Button, Typography, TextField, Box, CircularProgress, IconButton } from "@mui/material";
import { useState, useEffect,useRef } from "react";
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import CardActions from '@mui/material/CardActions';
import { styled } from '@mui/material/styles';
import SwipeableViews from '../components/swipableView';
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid';
import ThumbsUpDownIcon from '@mui/icons-material/ThumbsUpDown';
import EditableArtistPortfolio from "../components/editableArtistPortfolio";
import Popover from '@mui/material/Popover';
import ArtistDashboardRequest from "../components/artistDashboardRequest";
const SellerDashoard = (ctx) => {
const { user, isLoading } = useUser();
const [sellerData, setSellerData] = useState([]);
const [loading, setLoading] = useState(true); // State for loading indicator
const [isOnboarded, setIsOnboarded] = useState(false);
const [onBoardUrl, setOnBoardUrl] = useState("");
const [tabValue, setTabValue] = useState(1);
const getData = async () => {
const response = await fetch('/api/artist/profile');
const sellerProfile = await response.json();
setSellerData(sellerProfile);
const onboardCheckRequest = await fetch('/api/artist/onboarded', { method: "GET" });
const onboardCheckResponse = await onboardCheckRequest.json();
setIsOnboarded(onboardCheckResponse["onboarded"]);
const onboardUrlRequest = await fetch('/api/artist/onboardurl', { method: "GET" });
const onboardUrlResponse = await onboardUrlRequest.json();
setOnBoardUrl(onboardUrlResponse["onboardUrl"]);
setLoading(false); // Once data is fetched, set loading to false
}
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
setTabValue(newValue);
};
const handleChangeIndex = (index: number) => {
setTabValue(index);
};
interface TabPanelProps {
children?: React.ReactNode;
dir?: string;
index: number;
value: number;
}
function TabPanel(props: TabPanelProps) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`full-width-tabpanel-${index}`}
aria-labelledby={`full-width-tab-${index}`}
{...other}
>
{value === index && (
<Box sx={{ p: 3 }}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
function a11yProps(index: number) {
return {
id: `full-width-tab-${index}`,
'aria-controls': `full-width-tabpanel-${index}`,
};
}
useEffect(() => {
getData();
}, []);
const theme = useTheme();
const columns: GridColDef[] = [
{ field: 'requestor', headerName: 'User', width: 150 },
{ field: 'message', headerName: 'Message', width: 280 },
{ field: 'amount', headerName: 'Amount', width: 50 },
{
field: "action",
headerName: "Action",
sortable: false,
renderCell: (params) => {
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
const open = Boolean(anchorEl);
const id = open ? 'simple-popover' : undefined;
const buttonRef = useRef(null);
const accept = (e) => {
return alert("TEST");
};
const decline = (e) => {
return alert("TEST");
};
const handleClick = (e) => {
setAnchorEl(e.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
console.log(params)
return (
<>
<Button ref={buttonRef} startIcon={<ThumbsUpDownIcon/>} color="success" onClick={handleClick}></Button>
<Popover
id={params["requestor"]+"-"+params["amount"]}
open={open}
anchorEl={buttonRef.current}
onClose={handleClose}
transformOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
>
<Button size="small" color="success" variant="contained" onClick={accept}>Accept</Button>
<Button size="small" color="error" variant="contained" onClick={decline}>Decline</Button>
</Popover>
</>
)
}
}
];
const rows = [
{ id: 1, requestor: 'Snow', message: 'This is a test message!', amount: 35.00 },
{ id: 2, requestor: 'Lannister', message: 'This is a test message!', amount: 42.00 },
{ id: 3, requestor: 'Lannister', message: 'This is a test message!', amount: 45.00 },
{ id: 4, requestor: 'Stark', message: 'This is a test message!', amount: 16.00 },
{ id: 5, requestor: 'Targaryen', message: 'This is a test message!', amount: 150.00 },
{ id: 6, requestor: 'Melisandre', message: "This is a test message!", amount: 150.00 },
{ id: 7, requestor: 'Clifford', message: 'This is a test message!', amount: 44.00 },
{ id: 8, requestor: 'Frances', message: 'This is a test message!', amount: 36.00 },
{ id: 9, requestor: 'Roxie', message: 'This is a test message!', amount: 65.00 },
];
return (
<>
{loading ? ( // Render loading indicator if loading is true
<Box sx={{ textAlign: "center", paddingTop: 20 }}>
<Typography variant="h4" sx={{ textAlign: "center" }}>
Loading
</Typography>
<Box sx={{ paddingTop: 5 }} />
<CircularProgress />
</Box>
) : (
<Grid container >
{(Object.keys(sellerData).length > 0 ? (
<>
<Grid item container sx={{ textAlign: "center" }}>
<Grid item xs={12} sm={2} sx={{ textAlign: "center" }}>
<Button color="primary" variant="contained" href="../">
Back
</Button>
</Grid>
<Grid item xs={12} sm={8} sx={{ textAlign: "center" }}>
<Typography variant="h4">
Artist Dashboard
</Typography>
</Grid>
<Grid item xs={12} sm={2} sx={{ textAlign: "center" }}>
</Grid>
</Grid>
<ArtistDashboardRequest/>
</>
) : (
<></>
))}
<Grid item container xs={12} sm={12}>
</Grid>
</Grid>
)};
</>);
}
export default SellerDashoard;

83
pages/cards/index.tsx Normal file
View File

@ -0,0 +1,83 @@
// ** MUI Imports
import Grid from '@mui/material/Grid'
import Typography from '@mui/material/Typography'
// ** Demo Components Imports
import CardUser from '../views/cards/CardUser'
import CardImgTop from '../views/cards/CardImgTop'
import CardMobile from '../views/cards/CardMobile'
import CardSupport from '../views/cards/CardSupport'
import CardTwitter from '../views/cards/CardTwitter'
import CardFacebook from '../views/cards/CardFacebook'
import CardLinkedIn from '../views/cards/CardLinkedIn'
import CardAppleWatch from '../views/cards/CardAppleWatch'
import CardMembership from '../views/cards/CardMembership'
import CardInfluencer from '../views/cards/CardInfluencer'
import CardNavigation from '../views/cards/CardNavigation'
import CardWithCollapse from '../views/cards/CardWithCollapse'
import CardVerticalRatings from '../views/cards/CardVerticalRatings'
import CardNavigationCenter from '../views/cards/CardNavigationCenter'
import CardHorizontalRatings from '../views/cards/CardHorizontalRatings'
const CardBasic = () => {
return (
<Grid container spacing={6}>
<Grid item xs={12} sx={{ paddingBottom: 4 }}>
<Typography variant='h5'>Basic Cards</Typography>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardImgTop />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardUser />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardWithCollapse />
</Grid>
<Grid item xs={12} sm={6}>
<CardMobile />
</Grid>
<Grid item xs={12} sm={6}>
<CardHorizontalRatings />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardAppleWatch />
</Grid>
<Grid item xs={12} md={8}>
<CardMembership />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardInfluencer />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardVerticalRatings />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardSupport />
</Grid>
<Grid item xs={12} sx={{ pb: 4, pt: theme => `${theme.spacing(17.5)} !important` }}>
<Typography variant='h5'>Navigation Cards</Typography>
</Grid>
<Grid item xs={12} md={6}>
<CardNavigation />
</Grid>
<Grid item xs={12} md={6}>
<CardNavigationCenter />
</Grid>
<Grid item xs={12} sx={{ pb: 4, pt: theme => `${theme.spacing(17.5)} !important` }}>
<Typography variant='h5'>Solid Cards</Typography>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardTwitter />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardFacebook />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardLinkedIn />
</Grid>
</Grid>
)
}
export default CardBasic

View File

@ -0,0 +1,385 @@
import { withPageAuthRequired } from "@auth0/nextjs-auth0/client";
import Grid from '@mui/material/Grid';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import Button from '@mui/material/Button';
import { Accordion, Typography } from "@mui/material";
import { useEffect, useState } from "react";
import Switch from '@mui/material/Switch';
import Divider from '@mui/material/Divider';
import TextField from '@mui/material/TextField';
import { MuiColorInput } from 'mui-color-input'
import { AccordionSummary } from "@mui/material";
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import AccordionDetails from '@mui/material/AccordionDetails';
import Slider from '@mui/material/Slider';
import ArtistPortfolio from '../../../components/Old/artistPortfolio';
const Profile = () => {
const [profileData, setSellerProfileData] = useState(null);
const [backgroundColor, setBackgroundColor] = useState('rgb(126, 115, 115)');
const [headerColor, setHeaderColor] = useState('rgb(194, 187, 187)');
const [headerIsImage, setHeaderImage] = useState(false);
const [headerImageUrl, setHeaderImageUrl] = useState('');
const [headerText, setHeaderText] = useState('Shop');
const [headerSize, setHeaderSize] = useState(5);
const headerVariant = [
'h6', // Size 1
'h5', // Size 2
'h4', // Size 3
'h3', // Size 4
'h2', // Size 5
'h1', // Size 6
][headerSize - 1] || 'h6';
const [bioColor, setBioColor] = useState('rgb(186, 186, 186)');
const [bioBgColor, setBioBgColor] = useState('rgb(103, 97, 97)');
const [bioHeaderColor, setBioHeaderColor] = useState('rgb(255, 255, 255)');
const [bioHeaderIsImage, setBioHeaderImage] = useState(false);
const [bioHeaderImageUrl, setBioHeaderImageUrl] = useState('');
const [bioHeaderText, setBioHeaderText] = useState('Biography');
const [bioHeaderSize, setBioHeaderSize] = useState(3);
const [bioSize, setBioSize] = useState(1);
const bioHeaderVariant = [
'h6', // Size 1
'h5', // Size 2
'h4', // Size 3
'h3', // Size 4
'h2', // Size 5
'h1', // Size 6
][bioHeaderSize - 1] || 'h6';
const bioVariant = [
'h6', // Size 1
'h5', // Size 2
'h4', // Size 3
'h3', // Size 4
'h2', // Size 5
'h1', // Size 6
][bioSize - 1] || 'h6';
const [portfolioBgColor, setPortfolioBgColor] = useState('rgb(78, 73, 73)');
const [portfolioColumns, setPotrfolioColumns] = useState(2);
const [portfolioWoven, setPortfolioWoven] = useState(true);
const [portfolioShouldScroll, setPortfolioShouldScroll] = useState(true);
const [portfolioSize, setPortfolioSize] = useState(25);
const getData = async () => {
const profileResponse = await fetch('/api/artist/profile');
const sellerProfile = await profileResponse.json();
setSellerProfileData(sellerProfile);
}
useEffect(() => {
getData()
}, []);
const handleBackgroundColorChange = (newValue) => {
setBackgroundColor(newValue)
}
const handleHeaderTextChange = (e) => {
setHeaderText(e.target.value)
}
const handleHeaderImageUrl = (e) => {
setHeaderImageUrl(e.target.value)
}
const handleHeaderImageToggle = (e) => {
setHeaderImage(e.target.checked)
};
const handleHeaderSize = (e, newValue) => {
setHeaderSize(newValue)
}
const handleHeaderColorChange = (newValue) => {
setHeaderColor(newValue)
}
const handleBioHeaderTextChange = (e) => {
setBioHeaderText(e.target.value)
}
const handleBioHeaderImageUrl = (e) => {
setBioHeaderImageUrl(e.target.value)
}
const handleBioHeaderImageToggle = (e) => {
setBioHeaderImage(e.target.checked)
};
const handleBioHeaderSize = (e, newValue) => {
setBioHeaderSize(newValue)
}
const handleBioSize = (e, newValue) => {
setBioSize(newValue)
}
const handleBioHeaderColorChange = (newValue) => {
setBioHeaderColor(newValue)
}
const handleBioColorChange = (newValue) => {
setBioColor(newValue)
}
const handleBioBgColorChange = (newValue) => {
setBioBgColor(newValue)
}
const handlePortfolioBgColor = (newValue) => {
setPortfolioBgColor(newValue)
}
const handlePortfolioColumns = (e, newValue) => {
setPotrfolioColumns(newValue)
}
const handlePortfolioWoven = (e) => {
setPortfolioWoven(e.target.checked)
};
const handlePortfolioShouldScroll = (e) => {
setPortfolioShouldScroll(e.target.checked)
console.log(portfolioShouldScroll)
};
const handlePortfolioSize = (e, newValue) => {
setPortfolioSize(newValue)
}
return (
<Grid container spacing={2}>
<Grid item xs={12} md={4}>
<Card >
<CardContent>
<Grid container spacing={1}>
<Grid item xs={12} md={9}>
<Typography variant="h6" >
Customize Your Page
</Typography>
</Grid>
<Grid item xs={12} md={3}>
<Button variant="contained" size="large">
Save
</Button>
</Grid>
<Grid item xs={12} md={12}>
<Divider/>
</Grid>
<Grid item xs={12} md={12}>
<Accordion defaultExpanded>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1-content"
>
<Typography>Background</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={2}>
<Grid item xs={12} md={12}>
<MuiColorInput fullWidth value={backgroundColor} onChange={handleBackgroundColorChange} />
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>
<Grid item xs={12} md={12}>
<Accordion defaultExpanded>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1-content"
>
<Typography>Header</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={2}>
<Grid item xs={12} md={12}>
<TextField disabled={headerIsImage} variant="outlined" fullWidth label="Header Text" onChange={handleHeaderTextChange} value={headerText} size="small"></TextField>
</Grid>
<Grid item xs={12} md={10}>
<TextField variant="outlined" fullWidth label="Image Url" size="small" onChange={handleHeaderImageUrl}></TextField>
</Grid>
<Grid item xs={12} md={2}>
<Switch checked={headerIsImage} onChange={handleHeaderImageToggle} />
</Grid>
<Grid item xs={12} md={12}>
<MuiColorInput disabled={headerIsImage} label="Color" fullWidth value={headerColor} onChange={handleHeaderColorChange} />
</Grid>
<Grid item xs={12} md={3}>
<Typography variant="body1" >
Text Size
</Typography>
</Grid>
<Grid item xs={12} md={9}>
<Slider disabled={headerIsImage} value={headerSize} onChange={handleHeaderSize} aria-label="Size" defaultValue={6} step={1} marks min={1} max={6} />
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>
<Grid item xs={12} md={12}>
<Accordion defaultExpanded>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1-content"
>
<Typography>Biography</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={2}>
<Grid item xs={12} md={12}>
<TextField disabled={bioHeaderIsImage} variant="outlined" fullWidth label="Header Text" onChange={handleBioHeaderTextChange} value={bioHeaderText} size="small"></TextField>
</Grid>
<Grid item xs={12} md={10}>
<TextField variant="outlined" fullWidth label="Header Image Url" size="small" value={bioHeaderImageUrl} onChange={handleBioHeaderImageUrl}></TextField>
</Grid>
<Grid item xs={12} md={2}>
<Switch checked={bioHeaderIsImage} onChange={handleBioHeaderImageToggle} />
</Grid>
<Grid item xs={12} md={12}>
<MuiColorInput disabled={bioHeaderIsImage} label="Header Text Color" fullWidth value={bioHeaderColor} onChange={handleBioHeaderColorChange} />
</Grid>
<Grid item xs={12} md={12}>
<MuiColorInput label="Background Color" fullWidth value={bioBgColor} onChange={handleBioBgColorChange} />
</Grid>
<Grid item xs={12} md={12}>
<MuiColorInput label="Text Color" fullWidth value={bioColor} onChange={handleBioColorChange} />
</Grid>
<Grid item xs={12} md={5}>
<Typography variant="body1" >
Header Size
</Typography>
</Grid>
<Grid item xs={12} md={7}>
<Slider disabled={bioHeaderIsImage} value={bioHeaderSize} onChange={handleBioHeaderSize} aria-label="Size" defaultValue={6} step={1} marks min={1} max={6} />
</Grid>
<Grid item xs={12} md={5}>
<Typography variant="body1" >
Text Size
</Typography>
</Grid>
<Grid item xs={12} md={7}>
<Slider value={bioSize} onChange={handleBioSize} aria-label="Size" defaultValue={6} step={1} marks min={1} max={6} />
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>
<Grid item xs={12} md={12}>
<Accordion defaultExpanded>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1-content"
>
<Typography>Portfolio</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={2}>
<Grid item xs={12} md={12}>
<MuiColorInput label="Background Color" fullWidth value={portfolioBgColor} onChange={handlePortfolioBgColor} />
</Grid>
<Grid item xs={12} md={10}>
<Typography variant="body1" >
Masonry Layout Enabled
</Typography>
</Grid>
<Grid item xs={12} md={2 }>
<Switch checked={portfolioWoven} onChange={handlePortfolioWoven} />
</Grid>
<Grid item xs={12} md={5}>
<Typography variant="body1" >
Columns
</Typography>
</Grid>
<Grid item xs={12} md={7}>
<Slider value={portfolioColumns} onChange={handlePortfolioColumns} aria-label="Size" defaultValue={6} step={1} marks min={1} max={5} />
</Grid>
<Grid item xs={12} md={10}>
<Typography variant="body1" >
Enable Scrolling
</Typography>
</Grid>
<Grid item xs={12} md={2 }>
<Switch checked={portfolioShouldScroll} onChange={handlePortfolioShouldScroll} />
</Grid>
<Grid item xs={12} md={4}>
<Typography variant="body1" >
Max Size
</Typography>
</Grid>
<Grid item xs={12} md={8}>
<Slider disabled={!portfolioShouldScroll} value={portfolioSize} onChange={handlePortfolioSize} aria-label="Size" defaultValue={5} step={5} marks min={1} max={100} />
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>
</Grid>
</CardContent>
</Card>
</Grid>
<Grid item xs={12} md={8}>
<Grid container spacing={1}>
<Grid item xs={12} md={12}>
<Card sx={{backgroundColor:backgroundColor}}>
<CardContent>
<Grid container spacing={1}>
<Grid item xs={12} md={12} sx={{textAlign:"center"}}>
{(headerIsImage) ? (
<img src={headerImageUrl} alt="Header Image" />
) : (
<Typography variant={headerVariant} color={headerColor}>
{headerText}
</Typography>
)}
</Grid>
<Grid item xs={12} md={12} sx={{textAlign:"center", marginTop:"2%"}}>
<Card sx={{backgroundColor:bioBgColor}}>
<CardContent>
{(bioHeaderIsImage) ? (
<img src={bioHeaderImageUrl} alt="Header Image" />
) : (
<Typography variant={bioHeaderVariant} color={bioHeaderColor}>
{bioHeaderText}
</Typography>
)}
<Typography variant={bioVariant} color={bioColor} > {(profileData ? profileData["biography"]:null)}
</Typography>
</CardContent>
</Card>
</Grid>
<Grid item xs={12} md={12} sx={{textAlign:"center", marginTop:"2%"}}>
<Card sx={{backgroundColor:portfolioBgColor}}>
{(portfolioShouldScroll)?(
<CardContent sx={{height:`${portfolioSize}rem`, overflowY:"scroll",}}>
{(profileData ? (
<ArtistPortfolio masonry={portfolioWoven} columns={portfolioColumns} artistId={profileData["id"]} />
):null)}
</CardContent>
):(
<CardContent >
{(profileData ? (
<ArtistPortfolio masonry={portfolioWoven} columns={portfolioColumns} artistId={profileData["id"]} />
):null)}
</CardContent>
)}
</Card>
</Grid>
</Grid>
</CardContent>
</Card>
</Grid>
</Grid>
</Grid>
</Grid>
);
};
// Protected route, checking user authentication client-side.(CSR)
export default withPageAuthRequired(Profile);

121
pages/dashboard/index.tsx Normal file
View File

@ -0,0 +1,121 @@
// ** MUI Imports
import Grid from '@mui/material/Grid'
// ** Icons Imports
import Poll from 'mdi-material-ui/Poll'
import CurrencyUsd from 'mdi-material-ui/CurrencyUsd'
import HelpCircleOutline from 'mdi-material-ui/HelpCircleOutline'
import BriefcaseVariantOutline from 'mdi-material-ui/BriefcaseVariantOutline'
// ** Custom Components Imports
import CardStatisticsVerticalComponent from '../../core/components/card-statistics/card-stats-vertical'
// ** Styled Component Import
import ApexChartWrapper from '../../core/styles/libs/react-apexcharts'
import { Card, Typography } from '@mui/material'
import { withApiAuthRequired } from "@auth0/nextjs-auth0";
import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'
import Button from '@mui/material/Button'
import { CardContent } from '@mui/material'
import Onboarding from '../../components/Onboarding'
import { useState } from 'react'
import { useEffect } from 'react'
import { isObject } from 'util'
import Orders from '../../components/Orders'
const Dashboard = () => {
const [profileData, setSellerProfileData] = useState(null);
const [requestData, setSellerRequestData] = useState(null);
const [onboarding, setOnboarding] = useState(false);
const [onboarded, setOnboarded] = useState(false);
const setOnboardingTrue = () => {
setOnboarding(true);
}
const getData = async () => {
const profileResponse = await fetch('/api/artist/profile');
const sellerProfile = await profileResponse.json();
setSellerProfileData(sellerProfile);
const requestResponse = await fetch('/api/artist/request');
const sellerRequest = await requestResponse.json();
setSellerRequestData(sellerRequest);
setTimeout(getData, 5000); // Poll every 5 seconds (adjust as needed)
if(sellerRequest != null && Object.keys(sellerRequest).length>0){
setOnboarding(true)
}
if(sellerProfile!=null && Object.keys(sellerProfile).length>0 && sellerRequest["accepted"]){
setOnboarded(true)
}
}
useEffect(() => {
getData();
}, []);
return (
<ApexChartWrapper>
<Grid container spacing={6}>
<Grid item xs={12} md={6}>
<Card>
<CardContent>
<Grid container>
<Grid item xs={12} md={12} sx={{textAlign:"center"}}>
<Typography variant="h5" gutterBottom>
My Orders
</Typography>
</Grid>
<Grid item xs={12} md={12}>
<Orders />
</Grid>
</Grid>
</CardContent>
</Card>
</Grid>
{( onboarding==true && onboarded==false) ? (
<Grid item xs={12} md={6}>
<Onboarding />
</Grid>
):(
(onboarded) ? (
<Grid item xs={12} md={6}>
<Card sx={{textAlign:"center", width:"100%"}}>
<CardContent>
<Grid container>
<Grid item xs={12} md={12}>
<Typography>
THIS IS A TEST
</Typography>
</Grid>
</Grid>
</CardContent>
</Card>
</Grid>
) : (
<Grid item xs={12} md={6}>
<Card sx={{textAlign:"center", width:"100%"}}>
<CardContent>
<Grid container>
<Grid item xs={12} md={12}>
<Button color="primary" fullWidth variant="contained" onClick={setOnboardingTrue}>Become An Artist</Button>
</Grid>
</Grid>
</CardContent>
</Card>
</Grid>
)
)}
</Grid>
</ApexChartWrapper>
)
}
export default withPageAuthRequired(Dashboard)

View File

@ -0,0 +1,37 @@
// ** MUI Imports
import Grid from '@mui/material/Grid'
// ** Styled Component
import DatePickerWrapper from '../../core/styles/libs/react-datepicker'
// ** Demo Components Imports
import FormLayoutsBasic from '../../views/form-layouts/FormLayoutsBasic'
import FormLayoutsIcons from '../../views/form-layouts/FormLayoutsIcons'
import FormLayoutsSeparator from '../../views/form-layouts/FormLayoutsSeparator'
import FormLayoutsAlignment from '../../views/form-layouts/FormLayoutsAlignment'
// ** Third Party Styles Imports
import 'react-datepicker/dist/react-datepicker.css'
const FormLayouts = () => {
return (
<DatePickerWrapper>
<Grid container spacing={6}>
<Grid item xs={12} md={6}>
<FormLayoutsBasic />
</Grid>
<Grid item xs={12} md={6}>
<FormLayoutsIcons />
</Grid>
<Grid item xs={12}>
<FormLayoutsSeparator />
</Grid>
<Grid item xs={12}>
<FormLayoutsAlignment />
</Grid>
</Grid>
</DatePickerWrapper>
)
}
export default FormLayouts

Some files were not shown because too many files have changed in this diff Show More