mirror of
https://github.com/D4M13N-D3V/comissions-app-ui.git
synced 2025-03-14 08:15:08 +00:00
Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
01cc7eb197 | |||
2d4663ef74 | |||
![]() |
0807d6d11d | ||
![]() |
2a405067d8 | ||
![]() |
23ea8eed79 | ||
![]() |
8569290c0e | ||
![]() |
5a2f43768d | ||
![]() |
ff465278ad | ||
![]() |
a63d7f35b8 | ||
![]() |
93d4518500 | ||
![]() |
d52018f7eb | ||
![]() |
aac4ec902f | ||
![]() |
238477665d | ||
![]() |
b9aed8f3bb | ||
![]() |
565cb5dffb | ||
![]() |
539e1607bd | ||
![]() |
481bcd2d6c |
@ -4,6 +4,6 @@ AUTH0_CLIENT_SECRET="rCbTzrXdwZermb-N2GGqnCVI8YSTa32CA3GtuqZcmDRA6X0OGQGyiP4cRkh
|
||||
AUTH0_BASE_URL="http://localhost:3000"
|
||||
AUTH0_SECRET="rCbTzrXdwZermb-N2GGqnCVI8YSTa32CA3GtuqZcmDRA6X0OGQGyiP4cRkhBSIsd"
|
||||
AUTH0_AUDIENCE="https://api.artplatform.com"
|
||||
AUTH0_SCOPE="openid profile email read:user write:user read:billing-information write:billing-information read:seller-profile write:seller-profile read:seller-profile-request write:seller-profile-request read:seller-service write:seller-service read:orders write:orders read:seller-orders write:seller-orders"
|
||||
AUTH0_SCOPE="openid profile email read:user write:user read:request write:request read:artist write:artist"
|
||||
NEXT_PUBLIC_API_URL="https://core-api.development.comissions.app"
|
||||
REACT_EDITOR=atom
|
||||
|
@ -10,8 +10,7 @@ import Typography from '@mui/material/Typography';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import Drawer from '@mui/material/Drawer';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import ToggleColorMode from './ToggleColorMode';
|
||||
import { ArrowLeftOutlined, ArrowRightRounded, Logout, OpenInNew } from '@mui/icons-material';
|
||||
import { Logout, OpenInNew } from '@mui/icons-material';
|
||||
|
||||
const logoStyle = {
|
||||
width: '140px',
|
||||
@ -146,7 +145,7 @@ function AppAppBar({ user }: AppAppBarProps) {
|
||||
variant="contained"
|
||||
size="small"
|
||||
component="a"
|
||||
href="/api/auth/login"
|
||||
href="/dashboard"
|
||||
startIcon={<OpenInNew />}
|
||||
>
|
||||
Dashboard
|
||||
|
178
components/ArtistStats.tsx
Normal file
178
components/ArtistStats.tsx
Normal file
@ -0,0 +1,178 @@
|
||||
// ** React Imports
|
||||
import { ReactElement } from 'react'
|
||||
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box'
|
||||
import Grid from '@mui/material/Grid'
|
||||
import Card from '@mui/material/Card'
|
||||
import Avatar from '@mui/material/Avatar'
|
||||
import CardHeader from '@mui/material/CardHeader'
|
||||
import IconButton from '@mui/material/IconButton'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import CardContent from '@mui/material/CardContent'
|
||||
|
||||
// ** Icons Imports
|
||||
import TrendingUp from 'mdi-material-ui/TrendingUp'
|
||||
import CurrencyUsd from 'mdi-material-ui/CurrencyUsd'
|
||||
import DotsVertical from 'mdi-material-ui/DotsVertical'
|
||||
import CellphoneLink from 'mdi-material-ui/CellphoneLink'
|
||||
import AccountOutline from 'mdi-material-ui/AccountOutline'
|
||||
import CompareArrowsIcon from '@mui/icons-material/CompareArrows';
|
||||
|
||||
// ** Types
|
||||
import { ThemeColor } from '../core/layouts/types'
|
||||
import { Person } from '@mui/icons-material'
|
||||
|
||||
interface DataType {
|
||||
stats: string
|
||||
title: string
|
||||
color: ThemeColor
|
||||
icon: ReactElement
|
||||
}
|
||||
|
||||
const salesData: DataType[] = [
|
||||
{
|
||||
stats: '0',
|
||||
title: 'Pending',
|
||||
color: 'secondary',
|
||||
icon: <Person sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '0',
|
||||
title: 'Accepted',
|
||||
color: 'info',
|
||||
icon: <CompareArrowsIcon sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '0',
|
||||
color: 'error',
|
||||
title: 'Declined',
|
||||
icon: <CompareArrowsIcon sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '0',
|
||||
color: 'success',
|
||||
title: 'Completed',
|
||||
icon: <CurrencyUsd sx={{ fontSize: '1.75rem' }} />
|
||||
}
|
||||
]
|
||||
|
||||
const ArtistStats = ({profileData, stats}) => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
title='Artist Statistics'
|
||||
subheader={
|
||||
<>
|
||||
<Typography variant='body2'>
|
||||
<Box component='span' sx={{ fontWeight: 600, color: 'text.primary' }}>
|
||||
You have earned ${stats["revenue"]}
|
||||
</Box>{' '}
|
||||
😎 from {stats["paidRequests"]} requests.
|
||||
</Typography>
|
||||
<Typography variant='body2'>
|
||||
You have <b>{stats["pendingRequests"]}</b> pending requests.
|
||||
</Typography>
|
||||
</>
|
||||
}
|
||||
titleTypographyProps={{
|
||||
sx: {
|
||||
mb: 2.5,
|
||||
lineHeight: '2rem !important',
|
||||
letterSpacing: '0.15px !important'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<CardContent sx={{ pt: theme => `${theme.spacing(3)} !important` }}>
|
||||
<Grid container spacing={[5, 0]}>
|
||||
<Grid item xs={6} sm={3}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Avatar
|
||||
variant='rounded'
|
||||
sx={{
|
||||
mr: 3,
|
||||
width: 44,
|
||||
height: 44,
|
||||
boxShadow: 3,
|
||||
color: 'common.white',
|
||||
backgroundColor: `error.main`
|
||||
}}
|
||||
>
|
||||
<Person sx={{ fontSize: '1.75rem' }} />
|
||||
</Avatar>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography variant='caption'>Declined</Typography>
|
||||
<Typography variant='h6'>{stats["declinedRequests"]}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={6} sm={3}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Avatar
|
||||
variant='rounded'
|
||||
sx={{
|
||||
mr: 3,
|
||||
width: 44,
|
||||
height: 44,
|
||||
boxShadow: 3,
|
||||
color: 'common.white',
|
||||
backgroundColor: `info.main`
|
||||
}}
|
||||
>
|
||||
<Person sx={{ fontSize: '1.75rem' }} />
|
||||
</Avatar>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography variant='caption'>Accepted</Typography>
|
||||
<Typography variant='h6'>{stats["acceptedRequests"]}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={6} sm={3}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Avatar
|
||||
variant='rounded'
|
||||
sx={{
|
||||
mr: 3,
|
||||
width: 44,
|
||||
height: 44,
|
||||
boxShadow: 3,
|
||||
color: 'common.white',
|
||||
backgroundColor: `success.light`
|
||||
}}
|
||||
>
|
||||
<Person sx={{ fontSize: '1.75rem' }} />
|
||||
</Avatar>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography variant='caption'>Paid For</Typography>
|
||||
<Typography variant='h6'>{stats["completedRequests"]}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={6} sm={3}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Avatar
|
||||
variant='rounded'
|
||||
sx={{
|
||||
mr: 3,
|
||||
width: 44,
|
||||
height: 44,
|
||||
boxShadow: 3,
|
||||
color: 'common.white',
|
||||
backgroundColor: `success.dark`
|
||||
}}
|
||||
>
|
||||
<Person sx={{ fontSize: '1.75rem' }} />
|
||||
</Avatar>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography variant='caption'>Completed</Typography>
|
||||
<Typography variant='h6'>{stats["completedRequests"]}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default ArtistStats
|
@ -1,77 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import Card from '@mui/material/Card';
|
||||
import CardActions from '@mui/material/CardActions';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import CardMedia from '@mui/material/CardMedia';
|
||||
import StarBorderOutlinedIcon from '@mui/icons-material/StarBorderOutlined';
|
||||
import ShoppingCartCheckoutOutlinedIcon from '@mui/icons-material/ShoppingCartCheckoutOutlined';
|
||||
import AccountCircleOutlinedIcon from '@mui/icons-material/AccountCircleOutlined';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Item from '@mui/material/Grid';
|
||||
import Accordion from '@mui/material/Accordion';
|
||||
import AccordionSummary from '@mui/material/AccordionSummary';
|
||||
import AccordionDetails from '@mui/material/AccordionDetails';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import ArtistPortfolio from './artistPortfolio';
|
||||
import Button from '@mui/material/Button';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
|
||||
import { IconButton } from '@mui/material';
|
||||
|
||||
const Artist = ({user, artistId}) => {
|
||||
const [sellerData, setSellerData] = useState([]);
|
||||
useEffect(() => {
|
||||
const getData = async () => {
|
||||
const response = await fetch('/api/discovery/artist/'+artistId);
|
||||
const data = await response.json();
|
||||
setSellerData(data);
|
||||
}
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Card color="primary" sx={{margin:5}}>
|
||||
<CardContent>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6} md={8}>
|
||||
<Item>
|
||||
<Typography variant="h5" component="h2">
|
||||
{sellerData["name"]}
|
||||
</Typography>
|
||||
<Typography color="primary">
|
||||
{sellerData["averageRating"] ? `${sellerData["averageRating"]} Stars (${sellerData["reviewCount"]} Reviews)` : "No Reviews"}
|
||||
</Typography>
|
||||
<Typography variant="body2" component="p">
|
||||
{sellerData["biography"]}
|
||||
</Typography>
|
||||
</Item>
|
||||
|
||||
</Grid>
|
||||
<Grid item xs={6} md={4}>
|
||||
<Grid item xs={6} md={4}>
|
||||
<Button href={"artist/"+artistId} color="primary" variant='contained' sx={{width:160}}>View Profile</Button>
|
||||
{user ? (
|
||||
<Button color="secondary" variant='contained' href={"/artist/"+artistId+"/request"} sx={{ width: 160, marginTop:2 }}>Submit Request</Button>
|
||||
) : (
|
||||
<Tooltip title="Log in order to place a request.">
|
||||
<span>
|
||||
<Button disabled color="secondary" variant='contained' sx={{ width: 160, marginTop:2 }}>Submit Request</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
|
||||
<Item>
|
||||
</Item>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>)
|
||||
}
|
||||
export default Artist
|
@ -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
|
@ -1,28 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import ImageList from '@mui/material/ImageList';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { CircularProgress } from '@mui/material';
|
||||
|
||||
import { IconButton } from '@mui/material';
|
||||
|
||||
const ArtistPortfolioImage = ({artistId,itemId}) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<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}`}
|
||||
alt={itemId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor:'grey' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
</ImageListItem>)
|
||||
}
|
||||
export default ArtistPortfolioImage
|
211
components/dashboard/Onboarding.tsx
Normal file
211
components/dashboard/Onboarding.tsx
Normal file
@ -0,0 +1,211 @@
|
||||
import * as React from 'react';
|
||||
import {Box,Stepper,Step,StepLabel,StepContent,Button,Paper,Typography,Grid,TextField} from "@mui/material"
|
||||
import ArtistDashboardRequest from './artistRequest';
|
||||
import EditableArtistPortfolio from './artist/editablePortfolio';
|
||||
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, setArtistRequestData] = React.useState(null);
|
||||
const [profileData, setArtistData] = React.useState(null);
|
||||
const [isStripeOnboarded, setIsStripeOnboarded] = React.useState(false);
|
||||
const [onBoardUrl, setOnBoardUrl] = React.useState("");
|
||||
|
||||
const [requestMessage, setRequestMessage] = React.useState("");
|
||||
|
||||
const handleNext = () => {
|
||||
setActiveStep((prevActiveStep) => prevActiveStep + 1);
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
setActiveStep((prevActiveStep) => prevActiveStep - 1);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setActiveStep(0);
|
||||
};
|
||||
|
||||
const handleRequestMessage = (event) => {
|
||||
setRequestMessage(event.target.value);
|
||||
}
|
||||
|
||||
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();
|
||||
setArtistRequestData(sellerRequest);
|
||||
const profileResponse = await fetch('/api/artist/profile');
|
||||
const sellerProfile = await profileResponse.json();
|
||||
setArtistData(sellerProfile); // Poll every 5 seconds (adjust as needed)
|
||||
}
|
||||
React.useEffect(() => {
|
||||
getData();
|
||||
|
||||
setTimeout(getData, 30000);
|
||||
}, []);
|
||||
|
||||
const requestButton = () => {
|
||||
fetch('/api/artist/newRequest', {headers:{ "Content-Header":"application/json"},method:"POST",body:JSON.stringify(requestMessage)}).then((response) => {
|
||||
if (response.ok) {
|
||||
fetch('/api/artist/request').then((requestResponse) => {
|
||||
requestResponse.json().then((sellerRequest) => {
|
||||
setArtistRequestData(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 value={requestMessage} onChange={handleRequestMessage} 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>
|
||||
);
|
||||
}
|
49
components/dashboard/admin/artistRequest.tsx
Normal file
49
components/dashboard/admin/artistRequest.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import * as React from 'react';
|
||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid';
|
||||
import { Button } from '@mui/material';
|
||||
import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
||||
import { Grid, Typography } from "@mui/material";
|
||||
import Card from "@mui/material/Card";
|
||||
import CardContent from "@mui/material/CardContent";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
|
||||
|
||||
export default function AdminArtistRequest({id,userid,username,message,date,reload}) {
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}
|
||||
, []);
|
||||
|
||||
const getData = async () => {
|
||||
|
||||
}
|
||||
|
||||
const handleAccept = () => {
|
||||
fetch("/api/admin/requests/"+userid, {method:"PUT"}).then(response => response.json().then(data => {
|
||||
reload();
|
||||
}));
|
||||
}
|
||||
const handleDeny = () => {
|
||||
fetch("/api/admin/requests/"+userid, {method:"DELETE"}).then(response => response.json().then(data => {
|
||||
reload();
|
||||
}))
|
||||
}
|
||||
return (
|
||||
<Grid item xs={12} md={4}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography>ID: {id}</Typography>
|
||||
<Typography>User: {username}</Typography>
|
||||
<Typography>Message</Typography>
|
||||
<Typography>{message}</Typography>
|
||||
<Typography>Submitted Date {date}</Typography>
|
||||
<Button variant="contained" onClick={handleAccept} color="primary">Accept</Button>
|
||||
<Button variant="contained" onClick={handleDeny} color="secondary">Reject</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
);
|
||||
}
|
41
components/dashboard/artist/AssetImage.tsx
Normal file
41
components/dashboard/artist/AssetImage.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useState } from "react";
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
|
||||
const AssetImage = ({ assetId, requestId }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const url = "/api/artist/requests/"+requestId+"/assets/"+assetId
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={assetId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={url}
|
||||
src={url}
|
||||
alt={assetId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={url}
|
||||
alt={assetId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default AssetImage;
|
41
components/dashboard/artist/ReferenceImage.tsx
Normal file
41
components/dashboard/artist/ReferenceImage.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useState } from "react";
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
|
||||
const ReferenceImage = ({ referenceId, requestId }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const url = "/api/artist/requests/"+requestId+"/references/"+referenceId
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={referenceId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={url}
|
||||
src={url}
|
||||
alt={referenceId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={url}
|
||||
alt={referenceId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ReferenceImage;
|
96
components/dashboard/artist/editablePortfolio.tsx
Normal file
96
components/dashboard/artist/editablePortfolio.tsx
Normal file
@ -0,0 +1,96 @@
|
||||
import * as React from 'react';
|
||||
import { useEffect, useState } from "react";
|
||||
import { Grid, ImageList, Box, Tooltip, CircularProgress, Slider, IconButton } from '@mui/material';
|
||||
import { FileUpload } from '@mui/icons-material';
|
||||
import EditableArtistPortfolioImage from './editablePortfolioImage';
|
||||
|
||||
const EditableArtistPortfolio = ({ artistId }) => {
|
||||
const [portfolioData, setPortfolioData] = useState([]);
|
||||
const [columns, setColumns] = useState(2);
|
||||
const [loading, setLoading] = useState(true); // State for loading indicator
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
const handleColumns = (event, value)=>{
|
||||
setColumns(value);
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
const response = await fetch('/api/discovery/artist/' + artistId + '/portfolio');
|
||||
const data = await response.json();
|
||||
setPortfolioData(data);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
function handlePortfolioUploadImageChange(event) {
|
||||
const file = event.target.files[0];
|
||||
const formData = new FormData();
|
||||
formData.append('newImage', file);
|
||||
|
||||
fetch('/api/artist/portfolio', {
|
||||
method: 'POST',
|
||||
body: formData // Don't set Content-Type, FormData will handle it
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
getData();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error uploading file:', error);
|
||||
// Handle error appropriately
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
(loading) ? (
|
||||
<Box sx={{ textAlign: "center", paddingTop: 20 }}>
|
||||
<CircularProgress sx={{ paddingTop: 5 }} />
|
||||
</Box>
|
||||
) :
|
||||
(
|
||||
|
||||
<Grid container spacing={2} sm={12}>
|
||||
<Grid item xs={12} sm={1} sx={{ textAlign: "center" }}>
|
||||
<input
|
||||
id="portfolioUploadInput"
|
||||
style={{ display: 'none' }}
|
||||
accept="image/*"
|
||||
type="file"
|
||||
onChange={handlePortfolioUploadImageChange}
|
||||
/>
|
||||
<label htmlFor="portfolioUploadInput">
|
||||
<Tooltip arrow title="Upload Image To Portfolio">
|
||||
<IconButton color="primary" component="span">
|
||||
<FileUpload sx={{fontSize:"2rem"}}/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</label>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={11} sx={{ textAlign: "center" }}>
|
||||
<Tooltip arrow title="Amount of columns">
|
||||
<Slider
|
||||
defaultValue={columns}
|
||||
aria-labelledby="discrete-slider"
|
||||
valueLabelDisplay="auto"
|
||||
onChange={handleColumns}
|
||||
step={1}
|
||||
marks
|
||||
min={1}
|
||||
max={5}/>
|
||||
</Tooltip>
|
||||
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} sx={{maxHeight:"45rem",overflowY:"scroll"}}>
|
||||
<ImageList variant='masonry' cols={columns} sx={{ width:"100%" }}>
|
||||
{portfolioData.map((item) => (
|
||||
<EditableArtistPortfolioImage artistId={artistId} itemId={item.id} reload={getData}/>
|
||||
))}
|
||||
</ImageList>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
)
|
||||
)
|
||||
}
|
||||
export default EditableArtistPortfolio
|
59
components/dashboard/artist/editablePortfolioImage.tsx
Normal file
59
components/dashboard/artist/editablePortfolioImage.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
import * as React from 'react';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import { Dialog, DialogContent, ImageList,ImageListItem, ImageListItemBar } from '@mui/material';
|
||||
import { IconButton } from '@mui/material';
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const EditableArtistPortfolioImage = ({ artistId, itemId, reload }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false); // State for controlling the dialog
|
||||
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
const deleteButton = () => {
|
||||
setDeleting(true);
|
||||
fetch('/api/artist/portfolio/' + itemId + "/delete", {
|
||||
method: 'DELETE'
|
||||
}).then(response => {
|
||||
reload().then(data => {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={itemId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
alt={itemId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
<ImageListItemBar
|
||||
actionIcon={
|
||||
<IconButton onClick={deleteButton} color="error">
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
}>
|
||||
</ImageListItemBar>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
alt={itemId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditableArtistPortfolioImage;
|
@ -1,14 +1,14 @@
|
||||
import * as React from 'react';
|
||||
import {ImageList, Box, Typography, CircularProgress} from '@mui/material';
|
||||
import { useEffect, useState } from "react";
|
||||
import ArtistPortfolioImage from './artistPortfolioImage';
|
||||
|
||||
const ArtistPortfolio = ({artistId}) => {
|
||||
import ArtistPortfolioImage from './portfolioImage';
|
||||
const ArtistPortfolio = ({masonry,columns,artistId}) => {
|
||||
const [portfolioData, setPortfolioData] = useState([]);
|
||||
const [profileId, setArtistId] = useState(artistId)
|
||||
const [loading, setLoading] = useState(true); // State for loading indicator
|
||||
useEffect(() => {
|
||||
const getData = async () => {
|
||||
const response = await fetch('/api/discovery/artist/'+artistId+'/portfolio');
|
||||
const response = await fetch('/api/discovery/artist/'+profileId+'/portfolio');
|
||||
const data = await response.json();
|
||||
setPortfolioData(data);
|
||||
setLoading(false);
|
||||
@ -22,15 +22,24 @@ const ArtistPortfolio = ({artistId}) => {
|
||||
<Typography variant="h4" sx={{textAlign:"center"}}>
|
||||
Loading
|
||||
</Typography>
|
||||
<CircularProgress sx={{paddingTop:5}} />
|
||||
<Box sx={{paddingTop:"2%"}}/>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
) :
|
||||
(
|
||||
<ImageList cols={2} rowHeight={200} sx={{maxHeight:400}}>
|
||||
(masonry) ? (
|
||||
<ImageList variant='masonry' cols={columns} sx={{ width:"100%" }}>
|
||||
{portfolioData.map((item) => (
|
||||
<ArtistPortfolioImage artistId={artistId} itemId={item.id} />
|
||||
<ArtistPortfolioImage artistId={profileId} itemId={item.id} />
|
||||
))}
|
||||
</ImageList>
|
||||
):(
|
||||
<ImageList cols={columns} sx={{ width:"100%" }}>
|
||||
{portfolioData.map((item) => (
|
||||
<ArtistPortfolioImage artistId={profileId} itemId={item.id} />
|
||||
))}
|
||||
</ImageList>
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
41
components/dashboard/artist/portfolioImage.tsx
Normal file
41
components/dashboard/artist/portfolioImage.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useState } from "react";
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
|
||||
const ArtistPortfolioImage = ({ artistId, itemId }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={itemId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
alt={itemId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
alt={itemId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ArtistPortfolioImage;
|
85
components/dashboard/artist/reviews.tsx
Normal file
85
components/dashboard/artist/reviews.tsx
Normal file
@ -0,0 +1,85 @@
|
||||
import * as React from 'react';
|
||||
import { DataGrid } from '@mui/x-data-grid';
|
||||
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
||||
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Rating } from '@mui/material';
|
||||
|
||||
export default function Reviews({artistId}) {
|
||||
const router = useRouter();
|
||||
const columns = [
|
||||
{ field: 'requestId', headerName: 'ID', flex: 0.1},
|
||||
{ field: 'message', headerName: 'Review', flex: 0.5},
|
||||
{ field: 'rating', headerName: 'Rating', flex: 0.2, renderCell: (params) => {
|
||||
return <Rating value={params.row.rating} readOnly />;
|
||||
}}
|
||||
];
|
||||
const [isLoading, setIsLoading] = React.useState(true);
|
||||
const [reviewCount, setReviewCount] = React.useState(null);
|
||||
const [reviewData, setReviewData] = React.useState({});
|
||||
const [paginationModel, setPaginationModel] = React.useState({
|
||||
page: 0,
|
||||
pageSize: 15,
|
||||
});
|
||||
|
||||
|
||||
const getReviews = async () => {
|
||||
setIsLoading(true);
|
||||
const response = await fetch('/api/discovery/artist/'+artistId+'/reviews', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
// Assuming your API returns an array under a key like 'reviews'
|
||||
// Adjust this according to your actual API response structure
|
||||
const rows = data.reviews || []; // If 'reviews' doesn't exist, default to an empty array
|
||||
setReviewData(rows);
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
const getReviewsCount = async () => {
|
||||
const response = await fetch('/api/discovery/artist/'+artistId+'/reviewscount', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
setReviewCount(data);
|
||||
setRowCountState((prevRowCountState) =>
|
||||
data !== undefined
|
||||
? data
|
||||
: prevRowCountState,
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
// Some API clients return undefined while loading
|
||||
// Following lines are here to prevent `rowCountState` from being undefined during the loading
|
||||
const [rowCountState, setRowCountState] = React.useState(0);
|
||||
React.useEffect(() => {
|
||||
getReviews();
|
||||
getReviewsCount();
|
||||
}, [reviewCount, setRowCountState,paginationModel]);
|
||||
|
||||
return (
|
||||
|
||||
<div style={{ height: '100%', width: '100%' }}>
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||
<DataGrid
|
||||
getRowId={(row) => row.requestId}
|
||||
rows={reviewData}
|
||||
columns={columns}
|
||||
rowCount={rowCountState}
|
||||
loading={isLoading}
|
||||
pageSizeOptions={[15]}
|
||||
paginationModel={paginationModel}
|
||||
paginationMode="server"
|
||||
onPaginationModelChange={setPaginationModel}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
53
components/dashboard/artistRequest.tsx
Normal file
53
components/dashboard/artistRequest.tsx
Normal 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 ArtistOnboardRequest = () => {
|
||||
const [sellerRequestData, setArtistRequestData] = useState(null);
|
||||
|
||||
const getData = async () => {
|
||||
const response = await fetch('/api/artist/request');
|
||||
const sellerProfile = await response.json();
|
||||
setArtistRequestData(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 ArtistOnboardRequest
|
41
components/dashboard/customer/AssetImage.tsx
Normal file
41
components/dashboard/customer/AssetImage.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useState } from "react";
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
|
||||
const AssetImage = ({ assetId, requestId }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const url = "/api/requests/"+requestId+"/assets/"+assetId
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={assetId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={url}
|
||||
src={url}
|
||||
alt={assetId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={url}
|
||||
alt={assetId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default AssetImage;
|
41
components/dashboard/customer/ReferenceImage.tsx
Normal file
41
components/dashboard/customer/ReferenceImage.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useState } from "react";
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
|
||||
const ReferenceImage = ({ referenceId, requestId }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const url = "/api/requests/"+requestId+"/references/"+referenceId
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={referenceId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={url}
|
||||
src={url}
|
||||
alt={referenceId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={url}
|
||||
alt={referenceId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ReferenceImage;
|
137
components/dashboard/customer/orders.tsx
Normal file
137
components/dashboard/customer/orders.tsx
Normal file
@ -0,0 +1,137 @@
|
||||
import * as React from 'react';
|
||||
import { DataGrid } from '@mui/x-data-grid';
|
||||
import { GridColDef } from '@mui/x-data-grid';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import { Button, Typography } from '@mui/material';
|
||||
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
|
||||
import { DateField } from '@mui/x-date-pickers/DateField';
|
||||
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
||||
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import {Check, Refresh } from '@mui/icons-material';
|
||||
import PriceCheckIcon from '@mui/icons-material/PriceCheck';
|
||||
import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn';
|
||||
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
|
||||
import { useEffect, useState } from "react";
|
||||
import { useMediaQuery } from '@mui/material';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
|
||||
export default function CustomerOrders() {
|
||||
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm')); // Check if the screen size is small
|
||||
|
||||
const columns = [
|
||||
{ field: 'id', headerName: 'ID', flex: 0.1},
|
||||
{ field: 'status', headerName: 'Status', flex: 0.15,
|
||||
renderCell: (params) => {
|
||||
if(params.row.completed){
|
||||
return <Chip icon={<Check />} label="Completed" variant="outlined" color="success" />
|
||||
}
|
||||
else if(params.row.paid){
|
||||
return <Chip icon={<PriceCheckIcon />} label="Paid" variant="outlined" color="success" />
|
||||
}
|
||||
else if(params.row.accepted && params.row.paid==false){
|
||||
return <Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="outlined" color="warning" />
|
||||
}
|
||||
else if(params.row.accepted && params.row.paid){
|
||||
return <Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="outlined" color="info" />
|
||||
}
|
||||
else if(params.row.declined){
|
||||
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="outlined" color="error" />
|
||||
}
|
||||
else{
|
||||
return <Chip icon={<Refresh />} label="Pending" variant="outlined" color="secondary" />
|
||||
}
|
||||
}
|
||||
},
|
||||
{ field: 'amount', headerName: '$', flex: 0.1, renderCell: (params) => {
|
||||
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
|
||||
}},
|
||||
];
|
||||
if(!isSmallScreen){
|
||||
columns.push(
|
||||
{ field: 'requestDate', headerName: 'Request Date', flex:0.15, type: 'date' ,
|
||||
valueGetter: (params) => { return new Date(params.row.requestDate); }} );
|
||||
}
|
||||
const [isLoading, setIsLoading] = React.useState(true);
|
||||
const [requestCount, setRequestCount] = React.useState(null);
|
||||
const [requestData, setRequestData] = React.useState({});
|
||||
const [paginationModel, setPaginationModel] = React.useState({
|
||||
page: 0,
|
||||
pageSize: 5,
|
||||
});
|
||||
|
||||
|
||||
const getRequests = async () => {
|
||||
setIsLoading(true);
|
||||
const response = await fetch('/api/requests', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
completed: true, // Example query parameter
|
||||
declined: true, // Example query parameter
|
||||
accepted: true, // Example query parameter
|
||||
paid: true, // Example query parameter
|
||||
offset: paginationModel.page*paginationModel.pageSize, // Example query parameter
|
||||
pageSize: paginationModel.pageSize
|
||||
}),
|
||||
});
|
||||
const data = await response.json();
|
||||
setRequestData(data);
|
||||
setIsLoading(false);
|
||||
}
|
||||
const getRequestsCount = async () => {
|
||||
const response = await fetch('/api/requestcount', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
completed: true, // Example query parameter
|
||||
declined: true, // Example query parameter
|
||||
accepted: true, // Example query parameter
|
||||
paid: true, // Example query parameter
|
||||
offset: paginationModel.page*paginationModel.pageSize, // Example query parameter
|
||||
pageSize: paginationModel.pageSize
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
setRequestCount(data);
|
||||
setRowCountState((prevRowCountState) =>
|
||||
data !== undefined
|
||||
? data
|
||||
: prevRowCountState,
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
// Some API clients return undefined while loading
|
||||
// Following lines are here to prevent `rowCountState` from being undefined during the loading
|
||||
const [rowCountState, setRowCountState] = React.useState(0);
|
||||
React.useEffect(() => {
|
||||
getRequests();
|
||||
getRequestsCount();
|
||||
}, [requestCount, setRowCountState,paginationModel]);
|
||||
|
||||
return (
|
||||
<div style={{ width: '100%' }}>
|
||||
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||
<DataGrid
|
||||
minHeight={"500px"}
|
||||
rows={requestData}
|
||||
columns={columns}
|
||||
rowCount={rowCountState}
|
||||
loading={isLoading}
|
||||
pageSizeOptions={[5]}
|
||||
paginationModel={paginationModel}
|
||||
paginationMode="server"
|
||||
onPaginationModelChange={setPaginationModel}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { ImageList, Box, Button, CircularProgress } from '@mui/material';
|
||||
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
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
const getData = async () => {
|
||||
const response = await fetch('/api/discovery/artist/' + artistId + '/portfolio');
|
||||
const data = await response.json();
|
||||
setPortfolioData(data);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
function handlePortfolioUploadImageChange(event) {
|
||||
const file = event.target.files[0];
|
||||
const formData = new FormData();
|
||||
formData.append('newImage', file);
|
||||
|
||||
fetch('/api/artist/portfolio', {
|
||||
method: 'POST',
|
||||
body: formData // Don't set Content-Type, FormData will handle it
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
getData();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error uploading file:', error);
|
||||
// Handle error appropriately
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
(loading) ? (
|
||||
<Box sx={{ textAlign: "center", paddingTop: 20 }}>
|
||||
<CircularProgress sx={{ paddingTop: 5 }} />
|
||||
</Box>
|
||||
) :
|
||||
(
|
||||
|
||||
<Grid container spacing={2} sm={12}>
|
||||
<Grid item xs={12} sm={12} sx={{ textAlign: "center" }}>
|
||||
<input
|
||||
id="portfolioUploadInput"
|
||||
style={{ display: 'none' }}
|
||||
accept="image/*"
|
||||
type="file"
|
||||
onChange={handlePortfolioUploadImageChange}
|
||||
/>
|
||||
<label htmlFor="portfolioUploadInput">
|
||||
<Button
|
||||
fullWidth
|
||||
variant='outlined'
|
||||
component="span"
|
||||
size="small"
|
||||
sx={{width:"100%"}}
|
||||
startIcon={<FileOpenIcon />}
|
||||
>
|
||||
{(portfolioData.length > 0 ? "Upload Another Portfolio Image" : "Upload Your First Portfolio Image")}
|
||||
</Button>
|
||||
</label>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12}>
|
||||
<ImageList cols={2} rowHeight={200} sx={{ height: 400, width:"100%" }}>
|
||||
{portfolioData.map((item) => (
|
||||
<EditableArtistPortfolioImage artistId={artistId} itemId={item.id} reload={getData}/>
|
||||
))}
|
||||
</ImageList>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
)
|
||||
)
|
||||
}
|
||||
export default EditableArtistPortfolio
|
@ -1,48 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import ImageList from '@mui/material/ImageList';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useEffect, useState } from "react";
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
|
||||
import { CircularProgress, ImageListItemBar } from '@mui/material';
|
||||
|
||||
import { IconButton } from '@mui/material';
|
||||
|
||||
const EditableArtistPortfolioImage = ({artistId,itemId,reload}) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
|
||||
const deleteButton = () => {
|
||||
setDeleting(true);
|
||||
fetch('/api/artist/portfolio/'+itemId+"/delete", {
|
||||
method: 'DELETE'
|
||||
}).then(response => {
|
||||
reload().then(data => {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<ImageListItem key={itemId } sx={{maxWidth:300, maxHeight:300, overflow:"hidden"}}>
|
||||
<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}`}
|
||||
alt={itemId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor:'grey' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
<ImageListItemBar
|
||||
actionIcon={
|
||||
<IconButton onClick={deleteButton} color="error" >
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
}>
|
||||
</ImageListItemBar>
|
||||
</ImageListItem>)
|
||||
}
|
||||
export default EditableArtistPortfolioImage
|
@ -1,139 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { useUser } from "@auth0/nextjs-auth0/client";
|
||||
import AppBar from '@mui/material/AppBar';
|
||||
import Box from '@mui/material/Box';
|
||||
import Toolbar from '@mui/material/Toolbar';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import Container from '@mui/material/Container';
|
||||
import Button from '@mui/material/Button';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import { Chip, Icon } from '@mui/material';
|
||||
import {
|
||||
NovuProvider,
|
||||
PopoverNotificationCenter,
|
||||
NotificationBell,
|
||||
} from '@novu/notification-center';
|
||||
|
||||
|
||||
type HeaderProps = {
|
||||
user?: any;
|
||||
loading: boolean;
|
||||
};
|
||||
|
||||
|
||||
const settings = ['Seller Dashboard', 'Account', 'Dashboard', 'Logout'];
|
||||
|
||||
function ResponsiveAppBar() {
|
||||
const [anchorElNav, setAnchorElNav] = React.useState<null | HTMLElement>(null);
|
||||
const [anchorElUser, setAnchorElUser] = React.useState<null | HTMLElement>(null);
|
||||
|
||||
const handleOpenNavMenu = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorElNav(event.currentTarget);
|
||||
};
|
||||
const handleOpenUserMenu = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorElUser(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleCloseNavMenu = () => {
|
||||
setAnchorElNav(null);
|
||||
};
|
||||
|
||||
const handleCloseUserMenu = () => {
|
||||
setAnchorElUser(null);
|
||||
};
|
||||
|
||||
const { user, isLoading } = useUser();
|
||||
|
||||
return (
|
||||
<AppBar color="primary" position="static">
|
||||
<Container maxWidth="xl">
|
||||
<Toolbar disableGutters>
|
||||
<Box sx={{ flex:1, textAlign:"center" }}>
|
||||
<Typography
|
||||
href="/"
|
||||
variant="h6"
|
||||
noWrap
|
||||
color="secondary"
|
||||
component="a"
|
||||
sx={{
|
||||
mr: 2,
|
||||
paddingLeft: '1rem',
|
||||
display: { xs: 'flex', md: 'flex' },
|
||||
fontFamily: 'monospace',
|
||||
fontWeight: 700,
|
||||
letterSpacing: '0rem',
|
||||
textDecoration: 'none',
|
||||
}}
|
||||
>
|
||||
REQUEST.BOX
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{
|
||||
user ? (
|
||||
<>
|
||||
<Box>
|
||||
<NovuProvider subscriberId={'on-boarding-subscriber-id-123'} applicationIdentifier={'9SKjzgN_odAF'}>
|
||||
<PopoverNotificationCenter colorScheme={'light'}>
|
||||
{({ unseenCount }) => <NotificationBell unseenCount={unseenCount} />}
|
||||
</PopoverNotificationCenter>
|
||||
</NovuProvider>
|
||||
</Box>
|
||||
<Box>
|
||||
<Chip
|
||||
onClick={handleOpenUserMenu}
|
||||
label={user.name}
|
||||
color="secondary"
|
||||
variant={'outlined'}
|
||||
style={{ marginLeft: '10px', minWidth: '5rem', maxWidth:'10rem' }}
|
||||
/>
|
||||
<Menu
|
||||
sx={{ mt: '45px' }}
|
||||
id="menu-appbar"
|
||||
anchorEl={anchorElUser}
|
||||
anchorOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
keepMounted
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
open={Boolean(anchorElUser)}
|
||||
onClose={handleCloseUserMenu}
|
||||
>
|
||||
<MenuItem key="artistDashboard" onClick={handleCloseUserMenu}>
|
||||
<Button fullWidth color="secondary" variant='contained' href="/artistDashboard">Artist Dashboard</Button>
|
||||
</MenuItem>
|
||||
<MenuItem key="myOrders" onClick={handleCloseUserMenu}>
|
||||
<Button fullWidth color="primary" href="profile">My Orders</Button>
|
||||
</MenuItem>
|
||||
<MenuItem key="settings" onClick={handleCloseUserMenu}>
|
||||
<Button fullWidth color="primary" href="/settings">Settings</Button>
|
||||
</MenuItem>
|
||||
<MenuItem key="logout" onClick={handleCloseUserMenu}>
|
||||
<Button fullWidth color="error" href="/api/auth/logout">Logout</Button>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button key="login" href='/api/auth/login' onClick={handleCloseNavMenu} sx={{ my: 2, display: 'block', color:"white" }}>
|
||||
Login
|
||||
</Button>
|
||||
<Button key="signup" href='/api/auth/login' onClick={handleCloseNavMenu} sx={{ my: 2, display: 'block', color:"white" }}>
|
||||
Signup
|
||||
</Button>
|
||||
</>
|
||||
|
||||
)}
|
||||
|
||||
</Toolbar>
|
||||
</Container>
|
||||
</AppBar>
|
||||
);
|
||||
}
|
||||
export default ResponsiveAppBar;
|
@ -1,41 +0,0 @@
|
||||
import Head from "next/head";
|
||||
import Header from "./header";
|
||||
|
||||
type LayoutProps = {
|
||||
user?: any;
|
||||
loading?: boolean;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const Layout = ({ user, loading = false, children }: LayoutProps) => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>comissions.app</title>
|
||||
</Head>
|
||||
|
||||
<Header user={user} loading={loading} />
|
||||
|
||||
<main>
|
||||
<div className="container">{children}</div>
|
||||
</main>
|
||||
|
||||
<style jsx>{`
|
||||
.container {
|
||||
max-width: 82rem;
|
||||
margin: 1.5rem auto;
|
||||
}
|
||||
`}</style>
|
||||
<style jsx global>{`
|
||||
body {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
@ -1,31 +0,0 @@
|
||||
import { useEffect, useRef } from "react"
|
||||
|
||||
export default function SwipeableViews(
|
||||
{ className = "", index, onChangeIndex, ...rootProps }:
|
||||
{ index: number, onChangeIndex: (index: number) => void } & React.HTMLProps<HTMLDivElement>
|
||||
) {
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const scrollTimeout = useRef<number>()
|
||||
|
||||
useEffect(() => {
|
||||
containerRef.current?.children[index]?.scrollIntoView({ behavior: "smooth" })
|
||||
}, [index])
|
||||
|
||||
return (
|
||||
<div
|
||||
{...rootProps}
|
||||
ref={containerRef}
|
||||
className={
|
||||
"flex snap-x snap-mandatory items-stretch overflow-x-scroll " +
|
||||
"*:w-full *:flex-shrink-0 *:snap-center " + className
|
||||
}
|
||||
onScroll={({ currentTarget }) => {
|
||||
if (scrollTimeout.current) clearTimeout(scrollTimeout.current)
|
||||
scrollTimeout.current = window.setTimeout(() => {
|
||||
const pageWidth = currentTarget.scrollWidth / currentTarget.children.length
|
||||
onChangeIndex(Math.round(currentTarget.scrollLeft / pageWidth))
|
||||
}, 100)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
36
configs/themeConfig.tsx
Normal file
36
configs/themeConfig.tsx
Normal 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: 'dark' /* 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
|
@ -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'
|
||||
}
|
15
core/components/card-statistics/types.ts
Normal file
15
core/components/card-statistics/types.ts
Normal 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'
|
||||
}
|
7
core/components/react-apexcharts/index.tsx
Normal file
7
core/components/react-apexcharts/index.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
// ** Next Import
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
// ! To avoid 'Window is not defined' error
|
||||
const ReactApexcharts = dynamic(() => import('react-apexcharts'), { ssr: false })
|
||||
|
||||
export default ReactApexcharts
|
47
core/components/scroll-to-top/index.tsx
Normal file
47
core/components/scroll-to-top/index.tsx
Normal 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
|
47
core/context/settingsContext.tsx
Normal file
47
core/context/settingsContext.tsx
Normal 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
|
4
core/hooks/useSettings.ts
Normal file
4
core/hooks/useSettings.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { useContext } from 'react'
|
||||
import { SettingsContext, SettingsContextValue } from '../../core/context/settingsContext'
|
||||
|
||||
export const useSettings = (): SettingsContextValue => useContext(SettingsContext)
|
40
core/layouts/BlankLayout.tsx
Normal file
40
core/layouts/BlankLayout.tsx
Normal 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
|
118
core/layouts/VerticalLayout.tsx
Normal file
118
core/layouts/VerticalLayout.tsx
Normal 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
|
40
core/layouts/components/shared-components/ModeToggler.tsx
Normal file
40
core/layouts/components/shared-components/ModeToggler.tsx
Normal 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
|
@ -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
|
142
core/layouts/components/shared-components/UserDropdown.tsx
Normal file
142
core/layouts/components/shared-components/UserDropdown.tsx
Normal file
@ -0,0 +1,142 @@
|
||||
// ** React Imports
|
||||
import { useState, SyntheticEvent, Fragment, useEffect } 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();
|
||||
|
||||
const [appUser, setAppUser] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, []);
|
||||
|
||||
const getData = async () => {
|
||||
var userResponse = await fetch('/api/me');
|
||||
var user = await userResponse.json();
|
||||
setAppUser(user);
|
||||
}
|
||||
// ** 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 && appUser) ? (
|
||||
<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={appUser["displayName"]} 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 }}>{appUser["displayName"]}</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={() => router.push("/dashboard/settings")}>
|
||||
<Box sx={styles}>
|
||||
<CogOutline sx={{ marginRight: 2 }} />
|
||||
Settings
|
||||
</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
|
@ -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
|
57
core/layouts/components/shared-components/footer/index.tsx
Normal file
57
core/layouts/components/shared-components/footer/index.tsx
Normal 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
|
70
core/layouts/components/vertical/appBar/index.tsx
Normal file
70
core/layouts/components/vertical/appBar/index.tsx
Normal 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 '../../../../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
|
82
core/layouts/components/vertical/navigation/Drawer.tsx
Normal file
82
core/layouts/components/vertical/navigation/Drawer.tsx
Normal 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
|
@ -0,0 +1,74 @@
|
||||
// ** 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>
|
||||
<HeaderTitle variant='h6' sx={{ ml: 3 }}>
|
||||
{themeConfig.templateName}
|
||||
</HeaderTitle>
|
||||
</StyledLink>
|
||||
</Link>
|
||||
)}
|
||||
</MenuHeaderWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default VerticalNavHeader
|
@ -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
|
136
core/layouts/components/vertical/navigation/VerticalNavLink.tsx
Normal file
136
core/layouts/components/vertical/navigation/VerticalNavLink.tsx
Normal 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
|
@ -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
|
153
core/layouts/components/vertical/navigation/index.tsx
Normal file
153
core/layouts/components/vertical/navigation/index.tsx
Normal 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
46
core/layouts/types.ts
Normal 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
19
core/layouts/utils.ts
Normal 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
|
||||
}
|
103
core/styles/libs/react-apexcharts/index.ts
Normal file
103
core/styles/libs/react-apexcharts/index.ts
Normal file
@ -0,0 +1,103 @@
|
||||
// ** MUI imports
|
||||
import { styled } from '@mui/material/styles'
|
||||
|
||||
const ApexChartWrapper = styled('div')(({ theme }) => ({
|
||||
'& .apexcharts-canvas': {
|
||||
"& line[stroke='transparent']": {
|
||||
display: 'none'
|
||||
},
|
||||
'& .apexcharts-xaxis > line, & .apexcharts-yaxis > line': {
|
||||
stroke: theme.palette.divider
|
||||
},
|
||||
'& .apexcharts-xaxis-tick, & .apexcharts-yaxis-tick': {
|
||||
stroke: theme.palette.divider
|
||||
},
|
||||
'& .apexcharts-tooltip': {
|
||||
boxShadow: theme.shadows[3],
|
||||
borderColor: theme.palette.divider,
|
||||
background: theme.palette.background.paper,
|
||||
'& .apexcharts-tooltip-title': {
|
||||
fontWeight: 600,
|
||||
borderColor: theme.palette.divider,
|
||||
background: theme.palette.background.paper
|
||||
},
|
||||
'&.apexcharts-theme-dark': {
|
||||
'& .apexcharts-tooltip-text-label, & .apexcharts-tooltip-text-value': {
|
||||
color: theme.palette.common.white
|
||||
}
|
||||
},
|
||||
'& .bar-chart': {
|
||||
padding: theme.spacing(2, 2.5)
|
||||
}
|
||||
},
|
||||
'& .apexcharts-xaxistooltip': {
|
||||
borderColor: theme.palette.divider,
|
||||
background: theme.palette.mode === 'light' ? theme.palette.grey[50] : theme.palette.background.default,
|
||||
'& .apexcharts-xaxistooltip-text': {
|
||||
color: theme.palette.text.primary
|
||||
},
|
||||
'&:after': {
|
||||
borderBottomColor: theme.palette.mode === 'light' ? theme.palette.grey[50] : theme.palette.background.default
|
||||
},
|
||||
'&:before': {
|
||||
borderBottomColor: theme.palette.divider
|
||||
}
|
||||
},
|
||||
'& .apexcharts-yaxistooltip': {
|
||||
borderColor: theme.palette.divider,
|
||||
background: theme.palette.mode === 'light' ? theme.palette.grey[50] : theme.palette.background.default,
|
||||
'& .apexcharts-yaxistooltip-text': {
|
||||
color: theme.palette.text.primary
|
||||
},
|
||||
'&:after': {
|
||||
borderLeftColor: theme.palette.mode === 'light' ? theme.palette.grey[50] : theme.palette.background.default
|
||||
},
|
||||
'&:before': {
|
||||
borderLeftColor: theme.palette.divider
|
||||
}
|
||||
},
|
||||
'& .apexcharts-text, & .apexcharts-tooltip-text, & .apexcharts-datalabel-label, & .apexcharts-datalabel': {
|
||||
filter: 'none',
|
||||
fontWeight: 400,
|
||||
fill: theme.palette.text.primary,
|
||||
fontFamily: `${theme.typography.fontFamily} !important`
|
||||
},
|
||||
'& .apexcharts-pie-label': {
|
||||
filter: 'none',
|
||||
fill: theme.palette.common.white
|
||||
},
|
||||
'& .apexcharts-pie': {
|
||||
'& .apexcharts-datalabel-label, .apexcharts-datalabel-value': {
|
||||
fontSize: '1.5rem'
|
||||
}
|
||||
},
|
||||
'& .apexcharts-marker': {
|
||||
boxShadow: 'none'
|
||||
},
|
||||
'& .apexcharts-legend-series': {
|
||||
margin: `${theme.spacing(0.75, 2)} !important`,
|
||||
'& .apexcharts-legend-text': {
|
||||
marginLeft: theme.spacing(0.75),
|
||||
color: `${theme.palette.text.primary} !important`
|
||||
}
|
||||
},
|
||||
'& .apexcharts-xcrosshairs, & .apexcharts-ycrosshairs, & .apexcharts-gridline': {
|
||||
stroke: theme.palette.divider
|
||||
},
|
||||
'& .apexcharts-heatmap-rect': {
|
||||
stroke: theme.palette.mode === 'light' ? theme.palette.background.paper : theme.palette.background.default
|
||||
},
|
||||
'& .apexcharts-radialbar > g > g:first-of-type .apexcharts-radialbar-area': {
|
||||
stroke: theme.palette.background.default
|
||||
},
|
||||
'& .apexcharts-radar-series polygon': {
|
||||
stroke: theme.palette.divider,
|
||||
fill: theme.palette.background.paper
|
||||
},
|
||||
'& .apexcharts-radar-series line': {
|
||||
stroke: theme.palette.divider
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
export default ApexChartWrapper
|
361
core/styles/libs/react-datepicker/index.ts
Normal file
361
core/styles/libs/react-datepicker/index.ts
Normal 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
|
60
core/theme/ThemeComponent.tsx
Normal file
60
core/theme/ThemeComponent.tsx
Normal 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
|
58
core/theme/ThemeOptions.ts
Normal file
58
core/theme/ThemeOptions.ts
Normal 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
|
11
core/theme/breakpoints/index.ts
Normal file
11
core/theme/breakpoints/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
const breakpoints = () => ({
|
||||
values: {
|
||||
xs: 0,
|
||||
sm: 600,
|
||||
md: 900,
|
||||
lg: 1200,
|
||||
xl: 1536
|
||||
}
|
||||
})
|
||||
|
||||
export default breakpoints
|
47
core/theme/globalStyles.ts
Normal file
47
core/theme/globalStyles.ts
Normal 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
|
49
core/theme/overrides/accordion.ts
Normal file
49
core/theme/overrides/accordion.ts
Normal 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
|
112
core/theme/overrides/alerts.ts
Normal file
112
core/theme/overrides/alerts.ts
Normal 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
|
30
core/theme/overrides/avatars.ts
Normal file
30
core/theme/overrides/avatars.ts
Normal 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
|
25
core/theme/overrides/backdrop.ts
Normal file
25
core/theme/overrides/backdrop.ts
Normal 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
|
53
core/theme/overrides/button.ts
Normal file
53
core/theme/overrides/button.ts
Normal 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
|
86
core/theme/overrides/card.ts
Normal file
86
core/theme/overrides/card.ts
Normal 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
|
22
core/theme/overrides/chip.ts
Normal file
22
core/theme/overrides/chip.ts
Normal 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
|
64
core/theme/overrides/dateTimePicker.ts
Normal file
64
core/theme/overrides/dateTimePicker.ts
Normal 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
|
107
core/theme/overrides/dialog.ts
Normal file
107
core/theme/overrides/dialog.ts
Normal 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
|
16
core/theme/overrides/divider.ts
Normal file
16
core/theme/overrides/divider.ts
Normal 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
|
88
core/theme/overrides/index.ts
Normal file
88
core/theme/overrides/index.ts
Normal 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
|
65
core/theme/overrides/input.ts
Normal file
65
core/theme/overrides/input.ts
Normal 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
|
9
core/theme/overrides/link.ts
Normal file
9
core/theme/overrides/link.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export default {
|
||||
MuiLink: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
textDecoration: 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
core/theme/overrides/list.ts
Normal file
44
core/theme/overrides/list.ts
Normal 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
|
19
core/theme/overrides/menu.ts
Normal file
19
core/theme/overrides/menu.ts
Normal 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
|
41
core/theme/overrides/pagination.ts
Normal file
41
core/theme/overrides/pagination.ts
Normal 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
|
9
core/theme/overrides/paper.ts
Normal file
9
core/theme/overrides/paper.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export default {
|
||||
MuiPaper: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundImage: 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
core/theme/overrides/popover.ts
Normal file
18
core/theme/overrides/popover.ts
Normal 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
|
16
core/theme/overrides/rating.ts
Normal file
16
core/theme/overrides/rating.ts
Normal 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
|
12
core/theme/overrides/select.ts
Normal file
12
core/theme/overrides/select.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export default {
|
||||
MuiSelect: {
|
||||
styleOverrides: {
|
||||
select: {
|
||||
minWidth: '6rem !important',
|
||||
'&.MuiTablePagination-select': {
|
||||
minWidth: '1rem !important'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
16
core/theme/overrides/snackbar.ts
Normal file
16
core/theme/overrides/snackbar.ts
Normal 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
|
18
core/theme/overrides/switches.ts
Normal file
18
core/theme/overrides/switches.ts
Normal 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
|
69
core/theme/overrides/table.ts
Normal file
69
core/theme/overrides/table.ts
Normal 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
|
30
core/theme/overrides/tabs.ts
Normal file
30
core/theme/overrides/tabs.ts
Normal 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
|
83
core/theme/overrides/timeline.ts
Normal file
83
core/theme/overrides/timeline.ts
Normal 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
|
16
core/theme/overrides/toggleButton.ts
Normal file
16
core/theme/overrides/toggleButton.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export default {
|
||||
MuiToggleButtonGroup: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 4
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiToggleButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 4
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
core/theme/overrides/tooltip.ts
Normal file
28
core/theme/overrides/tooltip.ts
Normal 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
|
16
core/theme/overrides/typography.ts
Normal file
16
core/theme/overrides/typography.ts
Normal 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
111
core/theme/palette/index.ts
Normal 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
|
63
core/theme/shadows/index.ts
Normal file
63
core/theme/shadows/index.ts
Normal 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
|
3
core/theme/spacing/index.ts
Normal file
3
core/theme/spacing/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export default {
|
||||
spacing: (factor: number) => `${0.25 * factor}rem`
|
||||
}
|
18
core/theme/types.ts
Normal file
18
core/theme/types.ts
Normal 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 {}
|
67
core/theme/typography/index.ts
Normal file
67
core/theme/typography/index.ts
Normal 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
|
5
core/utils/create-emotion-cache.ts
Normal file
5
core/utils/create-emotion-cache.ts
Normal 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
16
core/utils/hex-to-rgba.ts
Normal 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
77
layouts/UserLayout.tsx
Normal 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
|
111
layouts/components/UpgradeToProButton.tsx
Normal file
111
layouts/components/UpgradeToProButton.tsx
Normal 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
|
29
layouts/components/UserIcon.tsx
Normal file
29
layouts/components/UserIcon.tsx
Normal 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
|
79
layouts/components/vertical/AppBarContent.tsx
Normal file
79
layouts/components/vertical/AppBarContent.tsx
Normal 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'
|
||||
import { useEffect, useState } from 'react'
|
||||
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'))
|
||||
|
||||
const [profileData, setProfileData] = useState(null);
|
||||
|
||||
const getData = async () => {
|
||||
const artistProfileRequest = await fetch('/api/me', { method: "GET" });
|
||||
const artistProfileResponse = await artistProfileRequest.json();
|
||||
setProfileData(artistProfileResponse);
|
||||
}
|
||||
|
||||
//console.log(profileData)
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []); return (
|
||||
<Box sx={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Box className='actions-left' sx={{ mr: 2, display: 'flex', alignItems: 'center' }}>
|
||||
{hidden ? (
|
||||
<IconButton
|
||||
color='inherit'
|
||||
onClick={toggleNavVisibility}
|
||||
sx={{ ml: -2.75, ...(hiddenSm ? {} : { mr: 3.5 }) }}
|
||||
>
|
||||
<Menu />
|
||||
</IconButton>
|
||||
) : null}
|
||||
</Box>
|
||||
<Box className='actions-right' sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
{(profileData ? (
|
||||
<NovuProvider subscriberId={profileData["id"]} applicationIdentifier={'9SKjzgN_odAF'}>
|
||||
<PopoverNotificationCenter colorScheme={'dark'}>
|
||||
{({ unseenCount }) => <NotificationBell unseenCount={unseenCount} />}
|
||||
</PopoverNotificationCenter>
|
||||
</NovuProvider>
|
||||
):null)}
|
||||
<UserDropdown />
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default AppBarContent
|
131
navigation/vertical/index.ts
Normal file
131
navigation/vertical/index.ts
Normal file
@ -0,0 +1,131 @@
|
||||
// ** 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 SettingsApplicationsIcon from '@mui/icons-material/SettingsApplications';
|
||||
import ListIcon from '@mui/icons-material/List';
|
||||
// ** Type import
|
||||
import { VerticalNavItemsType } from '../../core/layouts/types'
|
||||
import { BankTransfer, Cart, Clipboard, PageFirst, StarOutline } from 'mdi-material-ui'
|
||||
import { DocumentScanner, FileOpen, LockPerson, OpenInBrowser, People, PeopleOutline, Settings, WebAsset } from '@mui/icons-material'
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
const navigation = (): VerticalNavItemsType => {
|
||||
const [isStripeOnboarded, setIsStripeOnboarded] = useState(false);
|
||||
const [profileData, setProfileData] = useState(null);
|
||||
const [userData, setUserData] = useState(null);
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
|
||||
const getData = async () => {
|
||||
|
||||
const adminCheck = await fetch('/api/admin/check', { method: "GET" });
|
||||
if (adminCheck.status === 200) {
|
||||
setIsAdmin(true);
|
||||
}
|
||||
|
||||
const onboardCheckRequest = await fetch('/api/artist/onboarded', { method: "GET" });
|
||||
const onboardCheckResponse = await onboardCheckRequest.json();
|
||||
setIsStripeOnboarded(onboardCheckResponse["onboarded"]);
|
||||
|
||||
const artistProfileRequest = await fetch('/api/artist/profile', { method: "GET" });
|
||||
const artistProfileResponse = await artistProfileRequest.json();
|
||||
setProfileData(artistProfileResponse);
|
||||
|
||||
const userRequest = await fetch('/api/me', { method: "GET" });
|
||||
const userResponse = await userRequest.json();
|
||||
setUserData(userResponse);
|
||||
////console.log(roleResponse)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
var result = [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
icon: HomeOutline,
|
||||
path: '/dashboard'
|
||||
},
|
||||
{
|
||||
sectionTitle: 'General'
|
||||
},
|
||||
{
|
||||
title: 'Account Settings',
|
||||
icon: Settings,
|
||||
path: '/dashboard/settings'
|
||||
},
|
||||
{
|
||||
title: 'Your Requests',
|
||||
icon: ListIcon,
|
||||
path: '/dashboard/requests'
|
||||
}
|
||||
];
|
||||
|
||||
if (isAdmin) {
|
||||
result.push(
|
||||
{
|
||||
sectionTitle: 'Admin'
|
||||
},
|
||||
{
|
||||
title: 'Manage Artist Access',
|
||||
icon: LockPerson,
|
||||
path: '/dashboard/admin/requests'
|
||||
},
|
||||
{
|
||||
title: 'Manage Users',
|
||||
icon: People,
|
||||
path: '/dashboard/admin/users'
|
||||
},
|
||||
{
|
||||
title: 'Manage Artists',
|
||||
icon: PeopleOutline,
|
||||
path: '/dashboard/admin/artists'
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (isStripeOnboarded) {
|
||||
result.push(
|
||||
{
|
||||
sectionTitle: 'Artist'
|
||||
},
|
||||
{
|
||||
title: 'Request Reviews',
|
||||
icon: StarOutline,
|
||||
path: '/dashboard/artist/reviews'
|
||||
},
|
||||
{
|
||||
title: 'Incoming Requests',
|
||||
icon: ListIcon,
|
||||
path: '/dashboard/artist/requests'
|
||||
},
|
||||
{
|
||||
title: 'Payments/Payouts',
|
||||
icon: BankTransfer,
|
||||
path: '/dashboard/artist/payout'
|
||||
},
|
||||
{
|
||||
title: 'Artist Settings',
|
||||
icon: Settings,
|
||||
path: '/dashboard/artist/artistsettings'
|
||||
},
|
||||
{
|
||||
title: 'Page Settings',
|
||||
icon: WebAsset,
|
||||
path: '/dashboard/artist/pagesettings'
|
||||
},
|
||||
{
|
||||
title: 'Your Page',
|
||||
icon: OpenInBrowser,
|
||||
path: '/box/' + (userData ? userData["displayName"] : "")
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export default navigation;
|
||||
|
541
package-lock.json
generated
541
package-lock.json
generated
@ -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,25 @@
|
||||
"@mui/x-data-grid": "^6.19.4",
|
||||
"@mui/x-date-pickers": "^6.19.4",
|
||||
"@novu/notification-center": "^0.22.0",
|
||||
"@types/formidable": "^3.4.5",
|
||||
"apexcharts": "^3.45.2",
|
||||
"axios": "^1.6.7",
|
||||
"busboy": "^1.6.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"formidable": "^3.5.1",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"mdi-material-ui": "^7.8.0",
|
||||
"mui-color-input": "^2.0.2",
|
||||
"next": "latest",
|
||||
"node-fetch": "^3.3.2",
|
||||
"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 +142,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 +245,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",
|
||||
@ -1234,11 +1275,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@types/formidable": {
|
||||
"version": "3.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-3.4.5.tgz",
|
||||
"integrity": "sha512-s7YPsNVfnsng5L8sKnG/Gbb2tiwwJTY1conOkJzTMRvJAlLFW1nEua+ADsJQu8N1c0oTHx9+d5nqg10WuT9gHQ==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.19.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.10.tgz",
|
||||
"integrity": "sha512-IZD8kAM02AW1HRDTPOlz3npFava678pr8Ie9Vp8uRhBROXAv8MXT2pCnGZZAKYdromsNQLHQcfWQ6EOatVLtqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
@ -1290,6 +1338,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 +1374,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 +1442,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 +1521,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 +1576,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 +1601,23 @@
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"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 +1673,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",
|
||||
@ -1613,6 +1747,28 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-blob": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
||||
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"node-domexception": "^1.0.0",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20 || >= 14.13"
|
||||
}
|
||||
},
|
||||
"node_modules/find-root": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
||||
@ -1650,6 +1806,17 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||
"dependencies": {
|
||||
"fetch-blob": "^3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/formidable": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.1.tgz",
|
||||
@ -1716,6 +1883,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 +1949,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",
|
||||
@ -1797,6 +1984,14 @@
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
||||
},
|
||||
"node_modules/jwt-decode": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
|
||||
"integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/libphonenumber-js": {
|
||||
"version": "1.10.54",
|
||||
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.54.tgz",
|
||||
@ -1844,6 +2039,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 +2067,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 +2172,46 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||
"dependencies": {
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
}
|
||||
},
|
||||
"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 +2228,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 +2313,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 +2350,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 +2386,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 +2440,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 +2461,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 +2532,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 +2577,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 +2653,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 +2707,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 +2803,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",
|
||||
@ -2376,8 +2878,7 @@
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
||||
},
|
||||
"node_modules/url-join": {
|
||||
"version": "4.0.1",
|
||||
@ -2429,6 +2930,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 +2943,22 @@
|
||||
"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/web-streams-polyfill": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
||||
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/webfontloader": {
|
||||
"version": "1.6.28",
|
||||
"resolved": "https://registry.npmjs.org/webfontloader/-/webfontloader-1.6.28.tgz",
|
||||
@ -2475,6 +2997,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",
|
||||
|
16
package.json
16
package.json
@ -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,25 @@
|
||||
"@mui/x-data-grid": "^6.19.4",
|
||||
"@mui/x-date-pickers": "^6.19.4",
|
||||
"@novu/notification-center": "^0.22.0",
|
||||
"@types/formidable": "^3.4.5",
|
||||
"apexcharts": "^3.45.2",
|
||||
"axios": "^1.6.7",
|
||||
"busboy": "^1.6.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"formidable": "^3.5.1",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"mdi-material-ui": "^7.8.0",
|
||||
"mui-color-input": "^2.0.2",
|
||||
"next": "latest",
|
||||
"node-fetch": "^3.3.2",
|
||||
"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
65
pages/401.tsx
Normal 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′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
74
pages/404.tsx
Normal 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′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
74
pages/500.tsx
Normal 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
|
124
pages/_app.tsx
124
pages/_app.tsx
@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user