mirror of
https://github.com/D4M13N-D3V/comissions-app-ui.git
synced 2025-03-14 08:15:08 +00:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
01cc7eb197 | |||
2d4663ef74 | |||
![]() |
0807d6d11d | ||
![]() |
2a405067d8 | ||
![]() |
23ea8eed79 | ||
![]() |
8569290c0e | ||
![]() |
5a2f43768d | ||
![]() |
ff465278ad | ||
![]() |
a63d7f35b8 | ||
![]() |
93d4518500 | ||
![]() |
d52018f7eb | ||
![]() |
aac4ec902f | ||
![]() |
238477665d | ||
![]() |
b9aed8f3bb |
@ -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',
|
||||
|
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,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
|
@ -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 } >
|
||||
<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)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid';
|
||||
import { Button } from '@mui/material';
|
||||
|
||||
const columns: GridColDef[] = [
|
||||
{ field: 'id', headerName: 'ID', width: 70 },
|
||||
{ field: 'artist', headerName: 'Artist', width: 130 },
|
||||
{ field: 'status', headerName: 'Status', width: 130 },
|
||||
{ field: 'action', headerName: 'Action', width: 180, renderCell: (params) => {
|
||||
return (<Button variant="outlined" color="secondary" fullWidth>View More</Button>);
|
||||
}},
|
||||
];
|
||||
|
||||
const rows = [
|
||||
{ id: 1, artist:'Neroshi', status: 'Pending'},
|
||||
];
|
||||
|
||||
export default function Orders() {
|
||||
return (
|
||||
<div style={{ height: 400, width: '100%' }}>
|
||||
<DataGrid
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: { page: 0, pageSize: 5 },
|
||||
},
|
||||
}}
|
||||
pageSizeOptions={[5, 10]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
// ** 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: 'Customers',
|
||||
color: 'primary',
|
||||
icon: <Person sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '0',
|
||||
title: 'Accepted',
|
||||
color: 'success',
|
||||
icon: <CompareArrowsIcon sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '0',
|
||||
color: 'warning',
|
||||
title: 'Denied',
|
||||
icon: <CompareArrowsIcon sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '$0.00',
|
||||
color: 'info',
|
||||
title: 'Revenue',
|
||||
icon: <CurrencyUsd sx={{ fontSize: '1.75rem' }} />
|
||||
}
|
||||
]
|
||||
|
||||
const renderStats = () => {
|
||||
return salesData.map((item: DataType, index: number) => (
|
||||
<Grid item xs={12} sm={3} key={index}>
|
||||
<Box key={index} sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Avatar
|
||||
variant='rounded'
|
||||
sx={{
|
||||
mr: 3,
|
||||
width: 44,
|
||||
height: 44,
|
||||
boxShadow: 3,
|
||||
color: 'common.white',
|
||||
backgroundColor: `${item.color}.main`
|
||||
}}
|
||||
>
|
||||
{item.icon}
|
||||
</Avatar>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography variant='caption'>{item.title}</Typography>
|
||||
<Typography variant='h6'>{item.stats}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
))
|
||||
}
|
||||
|
||||
const SellerStats = () => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
title='Seller Statistics'
|
||||
subheader={
|
||||
<Typography variant='body2'>
|
||||
<Box component='span' sx={{ fontWeight: 600, color: 'text.primary' }}>
|
||||
Total 0% growth
|
||||
</Box>{' '}
|
||||
😎 this month
|
||||
</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]}>
|
||||
{renderStats()}
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default SellerStats
|
@ -1,19 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Stepper from '@mui/material/Stepper';
|
||||
import Step from '@mui/material/Step';
|
||||
import StepLabel from '@mui/material/StepLabel';
|
||||
import StepContent from '@mui/material/StepContent';
|
||||
import Button from '@mui/material/Button';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Grid from '@mui/material/Grid'
|
||||
import TextField from '@mui/material/TextField';
|
||||
import ArtistDashboardRequest from '../components/Old/artistDashboardRequest';
|
||||
import ArtistPortfolio from '../components/Old/artistPortfolio';
|
||||
import EditableArtistPortfolio from '../components/Old/editableArtistPortfolio';
|
||||
import {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';
|
||||
|
||||
@ -36,12 +25,12 @@ const steps = [
|
||||
|
||||
export default function Onboarding() {
|
||||
const [activeStep, setActiveStep] = React.useState(0);
|
||||
const [sellerRequestData, setSellerRequestData] = React.useState(null);
|
||||
const [profileData, setSellerProfileData] = React.useState(null);
|
||||
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);
|
||||
@ -55,6 +44,10 @@ export default function Onboarding() {
|
||||
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();
|
||||
@ -64,23 +57,23 @@ export default function Onboarding() {
|
||||
setOnBoardUrl(onboardUrlResponse["onboardUrl"]);
|
||||
const response = await fetch('/api/artist/request');
|
||||
const sellerRequest = await response.json();
|
||||
setSellerRequestData(sellerRequest);
|
||||
setArtistRequestData(sellerRequest);
|
||||
const profileResponse = await fetch('/api/artist/profile');
|
||||
const sellerProfile = await profileResponse.json();
|
||||
setSellerProfileData(sellerProfile);
|
||||
|
||||
setTimeout(getData, 5000); // Poll every 5 seconds (adjust as needed)
|
||||
setArtistData(sellerProfile); // Poll every 5 seconds (adjust as needed)
|
||||
}
|
||||
React.useEffect(() => {
|
||||
getData();
|
||||
|
||||
setTimeout(getData, 30000);
|
||||
}, []);
|
||||
|
||||
const requestButton = () => {
|
||||
fetch('/api/artist/newRequest').then((response) => {
|
||||
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) => {
|
||||
setSellerRequestData(sellerRequest);
|
||||
setArtistRequestData(sellerRequest);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -119,7 +112,7 @@ export default function Onboarding() {
|
||||
</Grid>
|
||||
):(
|
||||
<Grid item xs={12} lg={12}>
|
||||
<TextField fullWidth rows={4} multiline label="Application Message" variant="outlined" />
|
||||
<TextField value={requestMessage} onChange={handleRequestMessage} fullWidth rows={4} multiline label="Application Message" variant="outlined" />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
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;
|
@ -1,9 +1,9 @@
|
||||
import * as React from 'react';
|
||||
import { ImageList, Box, Button, CircularProgress, Slider } from '@mui/material';
|
||||
import { useEffect, useState } from "react";
|
||||
import EditableArtistPortfolioImage from './editableArtistPortfolioImage';
|
||||
import FileOpenIcon from '@mui/icons-material/FileOpen';
|
||||
import { Grid } from '@mui/material';
|
||||
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);
|
||||
@ -51,7 +51,7 @@ const EditableArtistPortfolio = ({ artistId }) => {
|
||||
(
|
||||
|
||||
<Grid container spacing={2} sm={12}>
|
||||
<Grid item xs={12} sm={12} sx={{ textAlign: "center" }}>
|
||||
<Grid item xs={12} sm={1} sx={{ textAlign: "center" }}>
|
||||
<input
|
||||
id="portfolioUploadInput"
|
||||
style={{ display: 'none' }}
|
||||
@ -60,19 +60,15 @@ const EditableArtistPortfolio = ({ artistId }) => {
|
||||
onChange={handlePortfolioUploadImageChange}
|
||||
/>
|
||||
<label htmlFor="portfolioUploadInput">
|
||||
<Button
|
||||
fullWidth
|
||||
variant='outlined'
|
||||
component="span"
|
||||
size="large"
|
||||
sx={{width:"100%"}}
|
||||
startIcon={<FileOpenIcon />}
|
||||
>
|
||||
{(portfolioData.length > 0 ? "Upload Another Portfolio Image" : "Upload Your First Portfolio Image")}
|
||||
</Button>
|
||||
<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={12} sx={{ textAlign: "center" }}>
|
||||
<Grid item xs={12} sm={11} sx={{ textAlign: "center" }}>
|
||||
<Tooltip arrow title="Amount of columns">
|
||||
<Slider
|
||||
defaultValue={columns}
|
||||
aria-labelledby="discrete-slider"
|
||||
@ -82,6 +78,8 @@ const EditableArtistPortfolio = ({ artistId }) => {
|
||||
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%" }}>
|
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';
|
||||
|
||||
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);
|
||||
@ -28,15 +28,15 @@ const ArtistPortfolio = ({masonry,columns,artistId}) => {
|
||||
) :
|
||||
(
|
||||
(masonry) ? (
|
||||
<ImageList variant="masonry" gap={8} cols={columns} sx={{overflowY:"scroll", maxWidth:"100%"}} >
|
||||
<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 gap={8} cols={columns} >
|
||||
{portfolioData.map((item) => (
|
||||
<ArtistPortfolioImage artistId={artistId} itemId={item.id} />
|
||||
<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>
|
||||
);
|
||||
}
|
@ -5,13 +5,13 @@ import CircularProgress from '@mui/material/CircularProgress';
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
|
||||
const ArtistDashboardRequest = () => {
|
||||
const [sellerRequestData, setSellerRequestData] = useState(null);
|
||||
const ArtistOnboardRequest = () => {
|
||||
const [sellerRequestData, setArtistRequestData] = useState(null);
|
||||
|
||||
const getData = async () => {
|
||||
const response = await fetch('/api/artist/request');
|
||||
const sellerProfile = await response.json();
|
||||
setSellerRequestData(sellerProfile);
|
||||
setArtistRequestData(sellerProfile);
|
||||
}
|
||||
useEffect(() => {
|
||||
getData();
|
||||
@ -50,4 +50,4 @@ const ArtistDashboardRequest = () => {
|
||||
))
|
||||
)
|
||||
}
|
||||
export default ArtistDashboardRequest
|
||||
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>
|
||||
);
|
||||
}
|
@ -18,7 +18,7 @@ type ThemeConfig = {
|
||||
const themeConfig: ThemeConfig = {
|
||||
// ** Layout Configs
|
||||
templateName: 'Request.Box' /* App Name */,
|
||||
mode: 'light' /* light | dark */,
|
||||
mode: 'dark' /* light | dark */,
|
||||
contentWidth: 'boxed' /* full | boxed */,
|
||||
|
||||
// ** Routing Configs
|
||||
|
@ -7,7 +7,7 @@ import MuiAppBar, { AppBarProps } from '@mui/material/AppBar'
|
||||
import MuiToolbar, { ToolbarProps } from '@mui/material/Toolbar'
|
||||
|
||||
// ** Type Import
|
||||
import { Settings } from '../core/context/settingsContext'
|
||||
import { Settings } from '../../../../context/settingsContext'
|
||||
|
||||
interface Props {
|
||||
hidden: boolean
|
||||
|
@ -61,7 +61,6 @@ const VerticalNavHeader = (props: Props) => {
|
||||
) : (
|
||||
<Link href='/' passHref>
|
||||
<StyledLink>
|
||||
<img width={30} height={25} src= "https://s6.imgcdn.dev/ttLwl.png"/>
|
||||
<HeaderTitle variant='h6' sx={{ ml: 3 }}>
|
||||
{themeConfig.templateName}
|
||||
</HeaderTitle>
|
||||
|
@ -23,7 +23,7 @@ import { Settings } from '../../../core/context/settingsContext'
|
||||
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
|
||||
@ -38,7 +38,18 @@ const AppBarContent = (props: Props) => {
|
||||
// ** Hook
|
||||
const hiddenSm = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm'))
|
||||
|
||||
return (
|
||||
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 ? (
|
||||
@ -52,12 +63,13 @@ const AppBarContent = (props: Props) => {
|
||||
) : null}
|
||||
</Box>
|
||||
<Box className='actions-right' sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
|
||||
<NovuProvider subscriberId={'on-boarding-subscriber-id-123'} applicationIdentifier={'9SKjzgN_odAF'}>
|
||||
<PopoverNotificationCenter colorScheme={'light'}>
|
||||
{(profileData ? (
|
||||
<NovuProvider subscriberId={profileData["id"]} applicationIdentifier={'9SKjzgN_odAF'}>
|
||||
<PopoverNotificationCenter colorScheme={'dark'}>
|
||||
{({ unseenCount }) => <NotificationBell unseenCount={unseenCount} />}
|
||||
</PopoverNotificationCenter>
|
||||
</NovuProvider>
|
||||
):null)}
|
||||
<UserDropdown />
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -4,83 +4,128 @@ 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, PageFirst } from 'mdi-material-ui'
|
||||
import { DocumentScanner, FileOpen, Settings } from '@mui/icons-material'
|
||||
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();
|
||||
}, []);
|
||||
|
||||
if(isStripeOnboarded){
|
||||
return [
|
||||
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: 'General'
|
||||
sectionTitle: 'Admin'
|
||||
},
|
||||
{
|
||||
title: 'Dashboard',
|
||||
icon: HomeOutline,
|
||||
path: '/dashboard'
|
||||
title: 'Manage Artist Access',
|
||||
icon: LockPerson,
|
||||
path: '/dashboard/admin/requests'
|
||||
},
|
||||
{
|
||||
title: 'Account Settings',
|
||||
icon: Settings,
|
||||
path: '/dashboard/settings'
|
||||
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: 'Shop Settings',
|
||||
icon: SettingsApplicationsIcon,
|
||||
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: 'Payout Portal',
|
||||
icon: BankTransfer,
|
||||
path: '/payoutportal'
|
||||
},
|
||||
{
|
||||
title: 'Page Settings',
|
||||
icon: DocumentScanner,
|
||||
icon: WebAsset,
|
||||
path: '/dashboard/artist/pagesettings'
|
||||
},
|
||||
{
|
||||
title: 'Preview Page',
|
||||
icon: FileOpen,
|
||||
path: '/artist/pagesettings'
|
||||
title: 'Your Page',
|
||||
icon: OpenInBrowser,
|
||||
path: '/box/' + (userData ? userData["displayName"] : "")
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
else{
|
||||
|
||||
return [
|
||||
{
|
||||
sectionTitle: 'General'
|
||||
},
|
||||
{
|
||||
title: 'Dashboard',
|
||||
icon: HomeOutline,
|
||||
path: '/dashboard'
|
||||
},
|
||||
{
|
||||
title: 'Account Settings',
|
||||
icon: Settings,
|
||||
path: '/dashboard/settings'
|
||||
},
|
||||
]
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export default navigation
|
||||
export default navigation;
|
||||
|
||||
|
109
package-lock.json
generated
109
package-lock.json
generated
@ -17,12 +17,17 @@
|
||||
"@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",
|
||||
@ -1270,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"
|
||||
}
|
||||
@ -1589,6 +1601,14 @@
|
||||
"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",
|
||||
@ -1727,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",
|
||||
@ -1764,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",
|
||||
@ -1931,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",
|
||||
@ -2111,6 +2172,41 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"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",
|
||||
@ -2782,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",
|
||||
@ -2856,6 +2951,14 @@
|
||||
"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",
|
||||
|
@ -18,12 +18,17 @@
|
||||
"@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",
|
||||
|
@ -1,103 +0,0 @@
|
||||
// ** React Imports
|
||||
import { SyntheticEvent, useState } from 'react'
|
||||
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box'
|
||||
import Card from '@mui/material/Card'
|
||||
import TabList from '@mui/lab/TabList'
|
||||
import TabPanel from '@mui/lab/TabPanel'
|
||||
import TabContext from '@mui/lab/TabContext'
|
||||
import { styled } from '@mui/material/styles'
|
||||
import MuiTab, { TabProps } from '@mui/material/Tab'
|
||||
|
||||
// ** Icons Imports
|
||||
import AccountOutline from 'mdi-material-ui/AccountOutline'
|
||||
import LockOpenOutline from 'mdi-material-ui/LockOpenOutline'
|
||||
import InformationOutline from 'mdi-material-ui/InformationOutline'
|
||||
|
||||
// ** Demo Tabs Imports
|
||||
import TabInfo from '../../views/account-settings/TabInfo'
|
||||
import TabAccount from '../../views/account-settings/TabAccount'
|
||||
import TabSecurity from '../../views/account-settings/TabSecurity'
|
||||
|
||||
// ** Third Party Styles Imports
|
||||
import 'react-datepicker/dist/react-datepicker.css'
|
||||
|
||||
const Tab = styled(MuiTab)<TabProps>(({ theme }) => ({
|
||||
[theme.breakpoints.down('md')]: {
|
||||
minWidth: 100
|
||||
},
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
minWidth: 67
|
||||
}
|
||||
}))
|
||||
|
||||
const TabName = styled('span')(({ theme }) => ({
|
||||
lineHeight: 1.71,
|
||||
fontSize: '0.875rem',
|
||||
marginLeft: theme.spacing(2.4),
|
||||
[theme.breakpoints.down('md')]: {
|
||||
display: 'none'
|
||||
}
|
||||
}))
|
||||
|
||||
const AccountSettings = () => {
|
||||
// ** State
|
||||
const [value, setValue] = useState<string>('account')
|
||||
|
||||
const handleChange = (event: SyntheticEvent, newValue: string) => {
|
||||
setValue(newValue)
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<TabContext value={value}>
|
||||
<TabList
|
||||
onChange={handleChange}
|
||||
aria-label='account-settings tabs'
|
||||
sx={{ borderBottom: theme => `1px solid ${theme.palette.divider}` }}
|
||||
>
|
||||
<Tab
|
||||
value='account'
|
||||
label={
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<AccountOutline />
|
||||
<TabName>Account</TabName>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
<Tab
|
||||
value='security'
|
||||
label={
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<LockOpenOutline />
|
||||
<TabName>Security</TabName>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
<Tab
|
||||
value='info'
|
||||
label={
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<InformationOutline />
|
||||
<TabName>Info</TabName>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
</TabList>
|
||||
|
||||
<TabPanel sx={{ p: 0 }} value='account'>
|
||||
<TabAccount />
|
||||
</TabPanel>
|
||||
<TabPanel sx={{ p: 0 }} value='security'>
|
||||
<TabSecurity />
|
||||
</TabPanel>
|
||||
<TabPanel sx={{ p: 0 }} value='info'>
|
||||
<TabInfo />
|
||||
</TabPanel>
|
||||
</TabContext>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default AccountSettings
|
@ -1,37 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useUser } from "@auth0/nextjs-auth0/client";
|
||||
import Layout from "../../components/OLd/layout";
|
||||
|
||||
const ApiProfile = () => {
|
||||
const { user, isLoading } = useUser();
|
||||
|
||||
const [data, setData] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const res = await fetch("/api/protected-api");
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
setData(data);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Layout user={user} loading={isLoading}>
|
||||
<h1>Profile</h1>
|
||||
|
||||
<div>
|
||||
<h3>Public page (client rendered)</h3>
|
||||
<p>We are fetching data on the client-side :</p>
|
||||
<p>By making request to '/api/protected-api' serverless function</p>
|
||||
<p>so without a valid session cookie will fail</p>
|
||||
<p>{JSON.stringify(data)}</p>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
// Public route.(CSR) also accessing API from the client-side.
|
||||
// data is not cached when redirecting between pages.
|
||||
export default ApiProfile;
|
@ -1,26 +0,0 @@
|
||||
import { withPageAuthRequired } from "@auth0/nextjs-auth0";
|
||||
import Layout from "../../components/Old/layout";
|
||||
import { User } from "../../interfaces";
|
||||
|
||||
type ProfileProps = {
|
||||
user: User;
|
||||
};
|
||||
|
||||
export default function Profile({ user }: ProfileProps) {
|
||||
return (
|
||||
<Layout user={user}>
|
||||
<h1>Profile</h1>
|
||||
|
||||
<div>
|
||||
<h3>Profile (server rendered)</h3>
|
||||
<img src={user.picture} alt="user picture" />
|
||||
<p>nickname: {user.nickname}</p>
|
||||
<p>name: {user.name}</p>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
// Protected route, checking authentication status before rendering the page.(SSR)
|
||||
// It's slower than a static page with client side authentication
|
||||
export const getServerSideProps = withPageAuthRequired();
|
18
pages/api/admin/artists.tsx
Normal file
18
pages/api/admin/artists.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { offset, pageSize } = req.body;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists?offset='+offset+'&pageSize='+pageSize, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
18
pages/api/admin/artists/[artistId].tsx
Normal file
18
pages/api/admin/artists/[artistId].tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { artistId } = req.query;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists/'+artistId, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/admin/artists/[artistId]/suspend.tsx
Normal file
19
pages/api/admin/artists/[artistId]/suspend.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { userId } = req.query;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists/'+userId+"/Suspend", {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/admin/artists/[artistId]/terminate.tsx
Normal file
19
pages/api/admin/artists/[artistId]/terminate.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { userId } = req.query;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists/'+userId+"/Terminate", {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/admin/artists/[artistId]/unsuspend.tsx
Normal file
19
pages/api/admin/artists/[artistId]/unsuspend.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { userId } = req.query;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists/'+userId+"/Unsuspend", {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
16
pages/api/admin/artists/count.tsx
Normal file
16
pages/api/admin/artists/count.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists/Count', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
12
pages/api/admin/check.tsx
Normal file
12
pages/api/admin/check.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtistRequests', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
res.status(response.status).json({})
|
||||
});
|
||||
|
18
pages/api/admin/requests.tsx
Normal file
18
pages/api/admin/requests.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { offset, pageSize } = req.body;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtistRequests?offset='+offset+'&pageSize='+pageSize, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
17
pages/api/admin/requests/[requestId].tsx
Normal file
17
pages/api/admin/requests/[requestId].tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { requestId } = req.query;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtistRequests/'+requestId, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
console.log(response)
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
||||
// handles ACCEPT AND DENY
|
16
pages/api/admin/requests/count.tsx
Normal file
16
pages/api/admin/requests/count.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtistRequests/Count', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
18
pages/api/admin/users.tsx
Normal file
18
pages/api/admin/users.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { offset, pageSize } = req.body;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers?offset='+offset+'&pageSize='+pageSize, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
18
pages/api/admin/users/[userId].tsx
Normal file
18
pages/api/admin/users/[userId].tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { userId } = req.query;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/'+userId, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/admin/users/[userId]/ban.tsx
Normal file
19
pages/api/admin/users/[userId]/ban.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { userId } = req.query;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/'+userId+"/Ban", {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/admin/users/[userId]/suspend.tsx
Normal file
19
pages/api/admin/users/[userId]/suspend.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { userId } = req.query;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/'+userId+"/Suspend", {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/admin/users/[userId]/unban.tsx
Normal file
19
pages/api/admin/users/[userId]/unban.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { userId } = req.query;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/'+userId+"/Unban", {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/admin/users/[userId]/unsuspend.tsx
Normal file
19
pages/api/admin/users/[userId]/unsuspend.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { userId } = req.query;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/'+userId+"/Unsuspend", {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
16
pages/api/admin/users/count.tsx
Normal file
16
pages/api/admin/users/count.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/Count', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
@ -2,11 +2,13 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a
|
||||
|
||||
export default withApiAuthRequired(async function products(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/SellerProfile', {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'POST'
|
||||
method: 'POST',
|
||||
body: req.body
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
16
pages/api/artist/artistAccessRequest.tsx
Normal file
16
pages/api/artist/artistAccessRequest.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function products(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'POST',
|
||||
body: req.body
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
@ -2,12 +2,15 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a
|
||||
|
||||
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/SellerProfile/Onboard', {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Onboard', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
@ -2,12 +2,14 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a
|
||||
|
||||
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/SellerProfile/Onboard/Url', {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Onboard/Url', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
29
pages/api/artist/page.tsx
Normal file
29
pages/api/artist/page.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function pageSettings(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
if(req.method !== 'GET') {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Page', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
method: "PUT",
|
||||
body: JSON.stringify(req.body)
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
||||
else{
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Page', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
|
||||
//console.log(response)
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
||||
});
|
||||
|
21
pages/api/artist/payout.tsx
Normal file
21
pages/api/artist/payout.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function products(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
////console.log(accessToken)
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Payout', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
method: 'GET'
|
||||
});
|
||||
if(response.status == 404)
|
||||
{
|
||||
res.status(200).json({})
|
||||
}
|
||||
else{
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
||||
});
|
||||
|
@ -26,7 +26,7 @@ export default withApiAuthRequired(async function handler(req, res) {
|
||||
const file = files["newImage"]; // Assuming your file input field name is 'file'
|
||||
try {
|
||||
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL + '/api/SellerProfile/Portfolio', {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL + '/api/Artist/Portfolio', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
|
@ -16,7 +16,7 @@ export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { id } = req.query;
|
||||
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL + '/api/SellerProfile/Portfolio/'+id, {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL + '/api/Artist/Portfolio/'+id, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
|
@ -2,13 +2,28 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a
|
||||
|
||||
export default withApiAuthRequired(async function sellerProfile(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/SellerProfile', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(req.method !== 'GET') {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
method: "PUT",
|
||||
body: req.body
|
||||
});
|
||||
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
||||
else{
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2,7 +2,8 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a
|
||||
|
||||
export default withApiAuthRequired(async function products(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/SellerProfile/Request', {
|
||||
////console.log(accessToken)
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Request', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
|
19
pages/api/artist/requestcount.tsx
Normal file
19
pages/api/artist/requestcount.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
|
||||
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Artist/Count?completed=${completed}&declined=${declined}&accepted=${accepted}&paid=${paid}&offset=${offset}&pageSize=${pageSize}`;
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/artist/requests.tsx
Normal file
19
pages/api/artist/requests.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
|
||||
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Artist?completed=${completed}&declined=${declined}&accepted=${accepted}&paid=${paid}&offset=${offset}&pageSize=${pageSize}`;
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
16
pages/api/artist/requests/[requestId]/accept.tsx
Normal file
16
pages/api/artist/requests/[requestId]/accept.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Accept', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'PUT'
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
22
pages/api/artist/requests/[requestId]/assets.tsx
Normal file
22
pages/api/artist/requests/[requestId]/assets.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
import { IncomingForm } from 'formidable';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
const file = await fs.readFile(path);
|
||||
return new Blob([file]);
|
||||
}
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Assets', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
24
pages/api/artist/requests/[requestId]/assets/[assetId].tsx
Normal file
24
pages/api/artist/requests/[requestId]/assets/[assetId].tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import axios from 'axios';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const assetId = req.query.assetId;
|
||||
const response = await axios({
|
||||
method: 'get',
|
||||
url: `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Artist/${requestId}/Assets/${assetId}`,
|
||||
responseType: 'stream',
|
||||
headers: {
|
||||
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
}
|
||||
})
|
||||
|
||||
res.setHeader('Content-Type', response.headers['content-type']);
|
||||
|
||||
// Pipe the response stream directly to the response of the Next.js API Route
|
||||
response.data.pipe(res);
|
||||
});
|
17
pages/api/artist/requests/[requestId]/complete.tsx
Normal file
17
pages/api/artist/requests/[requestId]/complete.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Complete', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'PUT'
|
||||
});
|
||||
console.log(response)
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
16
pages/api/artist/requests/[requestId]/deny.tsx
Normal file
16
pages/api/artist/requests/[requestId]/deny.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Deny', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'PUT'
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
16
pages/api/artist/requests/[requestId]/details.tsx
Normal file
16
pages/api/artist/requests/[requestId]/details.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'GET'
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
52
pages/api/artist/requests/[requestId]/newasset.tsx
Normal file
52
pages/api/artist/requests/[requestId]/newasset.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import { IncomingForm } from 'formidable'
|
||||
import fs from 'fs/promises';
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
const file = await fs.readFile(path);
|
||||
return new Blob([file]);
|
||||
}
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
|
||||
const form = new IncomingForm();
|
||||
const requestId = req.query.requestId;
|
||||
|
||||
form.parse(req, async (err, fields, files) => {
|
||||
if (err) {
|
||||
console.error('Error parsing form:', err);
|
||||
res.status(500).json({ error: 'Error parsing form' });
|
||||
return;
|
||||
}
|
||||
const file = files["newImage"]; // Assuming your file input field name is 'file'
|
||||
try {
|
||||
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Assets', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
"Content-Type": " application/octet-stream"
|
||||
},
|
||||
body: await createBlobFromFile(file[0].filepath) // Don't set Content-Type, FormData will handle it
|
||||
});
|
||||
|
||||
(response)
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.message || 'Failed to upload file');
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
res.status(200).json(responseData);
|
||||
} catch (error) {
|
||||
console.error('Error uploading file:', error);
|
||||
res.status(500).json({ error: 'Error uploading file' });
|
||||
}
|
||||
});
|
||||
});
|
22
pages/api/artist/requests/[requestId]/references.tsx
Normal file
22
pages/api/artist/requests/[requestId]/references.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
import { IncomingForm } from 'formidable';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
const file = await fs.readFile(path);
|
||||
return new Blob([file]);
|
||||
}
|
||||
export default withApiAuthRequired(async function products(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/References', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
@ -0,0 +1,24 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import axios from 'axios';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const referenceId = req.query.referenceId;
|
||||
const response = await axios({
|
||||
method: 'get',
|
||||
url: `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Artist/${requestId}/References/${referenceId}`,
|
||||
responseType: 'stream',
|
||||
headers: {
|
||||
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
}
|
||||
})
|
||||
|
||||
res.setHeader('Content-Type', response.headers['content-type']);
|
||||
|
||||
// Pipe the response stream directly to the response of the Next.js API Route
|
||||
response.data.pipe(res);
|
||||
});
|
19
pages/api/artist/reviews.tsx
Normal file
19
pages/api/artist/reviews.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
|
||||
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Artist/Reviews`;
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/artist/reviewscount.tsx
Normal file
19
pages/api/artist/reviewscount.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
|
||||
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Artist/Reviews/Count`;
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
21
pages/api/artist/stats.tsx
Normal file
21
pages/api/artist/stats.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function products(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
////console.log(accessToken)
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Stats', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
method: 'GET'
|
||||
});
|
||||
if(response.status == 404)
|
||||
{
|
||||
res.status(200).json({})
|
||||
}
|
||||
else{
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
||||
});
|
||||
|
14
pages/api/box/[artistName].tsx
Normal file
14
pages/api/box/[artistName].tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
|
||||
export default async function handler(req, res ): Promise<any> {
|
||||
const { artistName } = req.query;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${artistName}/Page`;
|
||||
const response = await fetch(url);
|
||||
//console.log(response)
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch seller');
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
34
pages/api/box/newRequest.tsx
Normal file
34
pages/api/box/newRequest.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import { getAccessToken } from '@auth0/nextjs-auth0';
|
||||
import fetch from 'node-fetch'; // Import node-fetch for making HTTP requests
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method === 'POST') {
|
||||
const url = process.env.NEXT_PUBLIC_API_URL + `/api/Requests/Request`;
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: req.body, // Pipe the incoming request directly to the outgoing request
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
res.status(response.status).json(errorData);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
console.error('Error occurred during fetch:', error);
|
||||
res.status(500).json({ error: 'An error occurred during the request' });
|
||||
}
|
||||
} else {
|
||||
res.status(405).json({ error: 'Method Not Allowed' });
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ import { useRouter } from 'next/router'
|
||||
|
||||
export default async function handler(req, res ): Promise<any> {
|
||||
const { sellerId } = req.query;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${sellerId}`;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch seller');
|
||||
|
@ -1,6 +1,6 @@
|
||||
export default async function handler(req, res ): Promise<any> {
|
||||
const { sellerId } = req.query;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${sellerId}/Portfolio`;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}/Portfolio`;
|
||||
(url)
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
|
13
pages/api/discovery/artist/[sellerId]/reviews.tsx
Normal file
13
pages/api/discovery/artist/[sellerId]/reviews.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
export default async function handler(req, res ): Promise<any> {
|
||||
const { sellerId } = req.query;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}/Reviews`;
|
||||
(url)
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch seller portfolio');
|
||||
}
|
||||
var result = await response.json();
|
||||
(result)
|
||||
res.status(200).json(result);
|
||||
}
|
||||
|
13
pages/api/discovery/artist/[sellerId]/reviewscount.tsx
Normal file
13
pages/api/discovery/artist/[sellerId]/reviewscount.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
export default async function handler(req, res ): Promise<any> {
|
||||
const { sellerId } = req.query;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}/Reviews/Count`;
|
||||
(url)
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch seller portfolio');
|
||||
}
|
||||
var result = await response.json();
|
||||
(result)
|
||||
res.status(200).json(result);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export default async function handler(req, res): Promise<any> {
|
||||
let url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers`;
|
||||
let url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch sellers');
|
||||
|
@ -3,9 +3,9 @@ import { withApiAuthRequired } from "@auth0/nextjs-auth0";
|
||||
import { getAccessToken } from '@auth0/nextjs-auth0';
|
||||
|
||||
|
||||
export default withApiAuthRequired(async function me(req, res) {
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
if(req.method !== 'GET') {
|
||||
console.log(req.body)
|
||||
////console.log(req.body)
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/User', {
|
||||
headers: {
|
||||
|
19
pages/api/requestcount.tsx
Normal file
19
pages/api/requestcount.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
|
||||
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Customer/Count?completed=${completed}&declined=${declined}&accepted=${accepted}&paid=${paid}&offset=${offset}&pageSize=${pageSize}`;
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/requests.tsx
Normal file
19
pages/api/requests.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
|
||||
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Customer?completed=${completed}&declined=${declined}&accepted=${accepted}&paid=${paid}&offset=${offset}&pageSize=${pageSize}`;
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
22
pages/api/requests/[requestId]/assets.tsx
Normal file
22
pages/api/requests/[requestId]/assets.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
import { IncomingForm } from 'formidable';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
const file = await fs.readFile(path);
|
||||
return new Blob([file]);
|
||||
}
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Assets', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
24
pages/api/requests/[requestId]/assets/[assetId].tsx
Normal file
24
pages/api/requests/[requestId]/assets/[assetId].tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import axios from 'axios';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const assetId = req.query.assetId;
|
||||
const response = await axios({
|
||||
method: 'get',
|
||||
url: `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Customer/${requestId}/Assets/${assetId}`,
|
||||
responseType: 'stream',
|
||||
headers: {
|
||||
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
}
|
||||
})
|
||||
|
||||
res.setHeader('Content-Type', response.headers['content-type']);
|
||||
|
||||
// Pipe the response stream directly to the response of the Next.js API Route
|
||||
response.data.pipe(res);
|
||||
});
|
16
pages/api/requests/[requestId]/details.tsx
Normal file
16
pages/api/requests/[requestId]/details.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'GET'
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
52
pages/api/requests/[requestId]/newreference.tsx
Normal file
52
pages/api/requests/[requestId]/newreference.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import { IncomingForm } from 'formidable'
|
||||
import fs from 'fs/promises';
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
const file = await fs.readFile(path);
|
||||
return new Blob([file]);
|
||||
}
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
|
||||
const form = new IncomingForm();
|
||||
const requestId = req.query.requestId;
|
||||
|
||||
form.parse(req, async (err, fields, files) => {
|
||||
if (err) {
|
||||
console.error('Error parsing form:', err);
|
||||
res.status(500).json({ error: 'Error parsing form' });
|
||||
return;
|
||||
}
|
||||
const file = files["newImage"]; // Assuming your file input field name is 'file'
|
||||
try {
|
||||
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/References', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
"Content-Type": " application/octet-stream"
|
||||
},
|
||||
body: await createBlobFromFile(file[0].filepath) // Don't set Content-Type, FormData will handle it
|
||||
});
|
||||
|
||||
(response)
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.message || 'Failed to upload file');
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
res.status(200).json(responseData);
|
||||
} catch (error) {
|
||||
console.error('Error uploading file:', error);
|
||||
res.status(500).json({ error: 'Error uploading file' });
|
||||
}
|
||||
});
|
||||
});
|
15
pages/api/requests/[requestId]/payment.tsx
Normal file
15
pages/api/requests/[requestId]/payment.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Payment', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
22
pages/api/requests/[requestId]/references.tsx
Normal file
22
pages/api/requests/[requestId]/references.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
import { IncomingForm } from 'formidable';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
const file = await fs.readFile(path);
|
||||
return new Blob([file]);
|
||||
}
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/References', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
24
pages/api/requests/[requestId]/references/[referenceId].tsx
Normal file
24
pages/api/requests/[requestId]/references/[referenceId].tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import axios from 'axios';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const referenceId = req.query.referenceId;
|
||||
const response = await axios({
|
||||
method: 'get',
|
||||
url: `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Customer/${requestId}/References/${referenceId}`,
|
||||
responseType: 'stream',
|
||||
headers: {
|
||||
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
}
|
||||
})
|
||||
|
||||
res.setHeader('Content-Type', response.headers['content-type']);
|
||||
|
||||
// Pipe the response stream directly to the response of the Next.js API Route
|
||||
response.data.pipe(res);
|
||||
});
|
17
pages/api/requests/[requestId]/review.tsx
Normal file
17
pages/api/requests/[requestId]/review.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Review', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(req.body)
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
257
pages/box/[artistName].tsx
Normal file
257
pages/box/[artistName].tsx
Normal file
@ -0,0 +1,257 @@
|
||||
import { withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Card from '@mui/material/Card';
|
||||
import CardActions from '@mui/material/CardActions';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import CardMedia from '@mui/material/CardMedia';
|
||||
import Button from '@mui/material/Button';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { useEffect, useState } from "react";
|
||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid';
|
||||
import Rating from '@mui/material/Rating';
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogContentText from '@mui/material/DialogContentText';
|
||||
import DialogActions from '@mui/material/DialogActions';
|
||||
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import ArtistPortfolio from "../../components/dashboard/artist/portfolio";
|
||||
import { RouterNetwork } from "mdi-material-ui";
|
||||
import { useRouter } from "next/router";
|
||||
import { profile } from "console";
|
||||
import FileOpen from "@mui/icons-material/FileOpen";
|
||||
import Reviews from "../../components/dashboard/artist/reviews";
|
||||
|
||||
const ArtistBox = () => {
|
||||
|
||||
const [profileData, setArtistData] = useState(null);
|
||||
const [description, setDescription] = useState("");
|
||||
const [guidelines, setGuidelines] = useState("");
|
||||
|
||||
const [requestMessage, setRequestMessage] = useState("");
|
||||
const [requestPrice, setRequestPrice] = useState(100.00);
|
||||
const [file, setFile] = useState(null);
|
||||
|
||||
const handleFileChange = (event) => {
|
||||
const files = event.target.files;
|
||||
setFile(files); // Set files to state
|
||||
}
|
||||
|
||||
|
||||
const handleRequestMessageChange = (event) => {
|
||||
setRequestMessage(event.target.value);
|
||||
}
|
||||
|
||||
const handleRequestPriceChange = (event) => {
|
||||
setRequestPrice(event.target.value);
|
||||
}
|
||||
|
||||
|
||||
const router = useRouter();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleClickOpen = () => {
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
const submitRequest = async (payload) => {
|
||||
|
||||
try {
|
||||
const requestResponse = await fetch('/api/box/newRequest', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
artistId: profileData["id"],
|
||||
message: payload.get('Message'),
|
||||
amount: payload.get('Amount'),
|
||||
})
|
||||
});
|
||||
if (requestResponse.ok) {
|
||||
const requestResponseData = await requestResponse.json();
|
||||
router.push("/dashboard/requests/"+requestResponseData["id"]);
|
||||
} else {
|
||||
const errorData = await requestResponse.json();
|
||||
alert("Error submitting request: " + errorData.detail);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error submitting request:', error);
|
||||
alert("Error submitting request. Please try again later.");
|
||||
}
|
||||
};
|
||||
|
||||
const getData = async () => {
|
||||
if(router.query.artistName!=null){
|
||||
const profileResponse = await fetch('/api/discovery/artist/'+router.query.artistName);
|
||||
const sellerProfile = await profileResponse.json();
|
||||
setArtistData(sellerProfile);
|
||||
|
||||
setDescription(sellerProfile["description"]);
|
||||
setGuidelines(sellerProfile["requestGuidelines"]);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, [router.query.artistName]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
PaperProps={{
|
||||
component: 'form',
|
||||
onSubmit: (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
const formData = new FormData(event.currentTarget);
|
||||
submitRequest(formData);
|
||||
handleClose();
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DialogTitle>New Request</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
Please read the guidelines of submitting a request before you proceed. You can do that by closing this popup and looking at the page behind.
|
||||
</DialogContentText>
|
||||
<TextField
|
||||
autoFocus
|
||||
required
|
||||
margin="dense"
|
||||
id="Message"
|
||||
name="Message"
|
||||
label="Request Message"
|
||||
type="message"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
multiline
|
||||
rows={10}
|
||||
onChange={handleRequestMessageChange}
|
||||
value={requestMessage}
|
||||
/>
|
||||
<CurrencyTextField
|
||||
label="Amount"
|
||||
variant="standard"
|
||||
currencySymbol="$"
|
||||
name="Amount"
|
||||
outputFormat="number"
|
||||
decimalCharacter="."
|
||||
digitGroupSeparator=","
|
||||
fullWidth
|
||||
onChange={handleRequestPriceChange}
|
||||
value={requestPrice}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose}>Cancel</Button>
|
||||
<Button type="submit">Submit Request</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Card>
|
||||
<CardMedia
|
||||
sx={{ height: "250px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
image="https://images.pexels.com/photos/255379/pexels-photo-255379.jpeg?cs=srgb&dl=pexels-miguel-%C3%A1-padri%C3%B1%C3%A1n-255379.jpg&fm=jpg"
|
||||
title="green iguana"
|
||||
>
|
||||
<Typography variant="h5" align="center" gutterBottom>STORE HEADER</Typography>
|
||||
</CardMedia>
|
||||
<CardContent>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={6} >
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h5" align="center" gutterBottom>BIOGRAPHY HEADER</Typography>
|
||||
<Typography variant="body2" align="center">
|
||||
{description}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} textAlign={"center"}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Typography variant="h5" align="center" gutterBottom>GUIDELINES HEADER</Typography>
|
||||
<Typography variant="body2" align="center">
|
||||
{guidelines}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Typography variant="caption" color={"error"} align="center" sx={{marginTop:"4%"}}>
|
||||
By clicking "Start New Request" you are agreeing to the terms above and to the terms of service.
|
||||
</Typography>
|
||||
<Typography variant="caption" color={"primary"} align="center" sx={{marginTop:"4%"}}>
|
||||
[TERMS OF SERVICE]
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Button onClick={handleClickOpen} size="large" variant="contained" color="primary" sx={{marginTop:"2%"}}>Start New Request</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Typography variant="h5" align="center" gutterBottom>REVIEWS HEADER</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
{profileData!=null ? (
|
||||
<Reviews artistId={profileData["id"]}/>
|
||||
):null}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6} >
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Typography variant="h5" align="center" gutterBottom>PORTFOLIO HEADER</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Typography variant="body2" align="center">
|
||||
{profileData!=null ? (
|
||||
<ArtistPortfolio masonry={true} columns={3} artistId={profileData["id"]} />
|
||||
):null}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// Protected route, checking user authentication client-side.(CSR)
|
||||
export default withPageAuthRequired(ArtistBox);
|
||||
|
||||
|
@ -1,83 +0,0 @@
|
||||
// ** MUI Imports
|
||||
import Grid from '@mui/material/Grid'
|
||||
import Typography from '@mui/material/Typography'
|
||||
|
||||
// ** Demo Components Imports
|
||||
import CardUser from '../views/cards/CardUser'
|
||||
import CardImgTop from '../views/cards/CardImgTop'
|
||||
import CardMobile from '../views/cards/CardMobile'
|
||||
import CardSupport from '../views/cards/CardSupport'
|
||||
import CardTwitter from '../views/cards/CardTwitter'
|
||||
import CardFacebook from '../views/cards/CardFacebook'
|
||||
import CardLinkedIn from '../views/cards/CardLinkedIn'
|
||||
import CardAppleWatch from '../views/cards/CardAppleWatch'
|
||||
import CardMembership from '../views/cards/CardMembership'
|
||||
import CardInfluencer from '../views/cards/CardInfluencer'
|
||||
import CardNavigation from '../views/cards/CardNavigation'
|
||||
import CardWithCollapse from '../views/cards/CardWithCollapse'
|
||||
import CardVerticalRatings from '../views/cards/CardVerticalRatings'
|
||||
import CardNavigationCenter from '../views/cards/CardNavigationCenter'
|
||||
import CardHorizontalRatings from '../views/cards/CardHorizontalRatings'
|
||||
|
||||
const CardBasic = () => {
|
||||
return (
|
||||
<Grid container spacing={6}>
|
||||
<Grid item xs={12} sx={{ paddingBottom: 4 }}>
|
||||
<Typography variant='h5'>Basic Cards</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<CardImgTop />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<CardUser />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<CardWithCollapse />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<CardMobile />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<CardHorizontalRatings />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<CardAppleWatch />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={8}>
|
||||
<CardMembership />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<CardInfluencer />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<CardVerticalRatings />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<CardSupport />
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{ pb: 4, pt: theme => `${theme.spacing(17.5)} !important` }}>
|
||||
<Typography variant='h5'>Navigation Cards</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<CardNavigation />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<CardNavigationCenter />
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{ pb: 4, pt: theme => `${theme.spacing(17.5)} !important` }}>
|
||||
<Typography variant='h5'>Solid Cards</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<CardTwitter />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<CardFacebook />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={4}>
|
||||
<CardLinkedIn />
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
export default CardBasic
|
151
pages/dashboard/admin/artists.tsx
Normal file
151
pages/dashboard/admin/artists.tsx
Normal file
@ -0,0 +1,151 @@
|
||||
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, Stack, 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 {Block, Check, Close, Download, OpenInFull, OpenInNew, Refresh, Star, Upload } 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 ShoppingCartCheckoutIcon from '@mui/icons-material/ShoppingCartCheckout';
|
||||
import { IconButton } from '@mui/material';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import { Card, CardContent } from '@mui/material';
|
||||
import Rating from '@mui/material/Rating';
|
||||
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import { DownloadBox, Magnify, StarOutline } from 'mdi-material-ui';
|
||||
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material';
|
||||
import { Grid } from '@mui/material';
|
||||
import { useRouter } from 'next/router';
|
||||
import { request } from 'http';
|
||||
import { useMediaQuery } from '@mui/material';
|
||||
|
||||
|
||||
export default function AdminArtists() {
|
||||
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm')); // Check if the screen size is small
|
||||
const router = useRouter();
|
||||
let columns = [];
|
||||
if(isSmallScreen){
|
||||
columns = [
|
||||
{ field: 'id', headerName: '', flex: 0.05, sortable: false, filterable: false},
|
||||
];
|
||||
}
|
||||
else{
|
||||
columns = [
|
||||
{ field: 'id', headerName: '', flex: 0.05, sortable: false, filterable: false},
|
||||
{ field: 'displayName', headerName: 'User Name', flex: 0.15, sortable: false, filterable: false, valueGetter: (params) => {
|
||||
return params.row.user.displayName
|
||||
}},
|
||||
{ field: 'name', headerName: 'Artist Name', flex: 0.15, sortable: false, filterable: false, valueGetter: (params) => {
|
||||
return params.row.name
|
||||
}},
|
||||
{ field: 'email', headerName: 'Email', flex: 0.15, sortable: false, filterable: false, valueGetter: (params) => {
|
||||
return params.row.user.email
|
||||
}},
|
||||
{ field: 'numberOfRequests', headerName: '# of Requests', flex: 0.1, sortable: false, filterable: false},
|
||||
{ field: 'averageRating', headerName: 'Average Rating', flex: 0.1, sortable: false, filterable: false},
|
||||
{ field: 'amountMade', headerName: 'Amount Made', flex: 0.1, sortable: false, filterable: false},
|
||||
{ field: 'feesCollected', headerName: 'Fees Collected', flex: 0.1, sortable: false, filterable: false},
|
||||
{ field: 'status', headerName: 'Status', flex: 0.1, sortable: false, filterable: false, renderCell: (params) =>{
|
||||
if(params.row.user.banned){
|
||||
return <Chip icon={<Block />} label="Banned" variant="outlined" color="error" />
|
||||
}
|
||||
else if(params.row.suspended || params.row.user.suspended){
|
||||
return <Chip icon={<Block />} label="Suspended" variant="outlined" color="error" />
|
||||
}
|
||||
else{
|
||||
return <Chip icon={<Check />} label="Active" variant="outlined" color="success" />
|
||||
}
|
||||
}},
|
||||
{ field: 'actions', headerName: '', flex: 0.05, sortable: false, filterable: false, renderCell: (params) => {
|
||||
return <Tooltip title="View more information about this user."><IconButton color="info" onClick={() => router.push("/dashboard/admin/artists/"+params.row.id)}><OpenInNew /></IconButton></Tooltip>
|
||||
}}
|
||||
];
|
||||
}
|
||||
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: 15,
|
||||
});
|
||||
|
||||
|
||||
const getRequests = async () => {
|
||||
setIsLoading(true);
|
||||
const response = await fetch('/api/admin/artists', {
|
||||
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/admin/artists/count', {
|
||||
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={{ height: '100%', width: '100%' }}>
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||
<DataGrid
|
||||
rows={requestData}
|
||||
columns={columns}
|
||||
rowCount={rowCountState}
|
||||
loading={isLoading}
|
||||
pageSizeOptions={[15]}
|
||||
paginationModel={paginationModel}
|
||||
paginationMode="server"
|
||||
onPaginationModelChange={setPaginationModel}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
104
pages/dashboard/admin/artists/[artistId].tsx
Normal file
104
pages/dashboard/admin/artists/[artistId].tsx
Normal file
@ -0,0 +1,104 @@
|
||||
import * as React from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'
|
||||
import { Alert, Card, CardContent, Grid, IconButton, TextField, Typography } from '@mui/material';
|
||||
import { ArrowBack, ArrowLeft, Block, Close } from '@mui/icons-material';
|
||||
import Button from '@mui/material/Button';
|
||||
import { OpenInNew } from 'mdi-material-ui';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
|
||||
const AdminArtist = () => {
|
||||
const router = useRouter();
|
||||
|
||||
|
||||
const [artist, setArtist] = useState(null);
|
||||
|
||||
const getData = async () => {
|
||||
if(router.query.artistId!=null){
|
||||
const response = await fetch("/api/admin/artists/"+router.query.artistId);
|
||||
const data = await response.json();
|
||||
setArtist(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, [router.query.artistId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="h5">Artist Information</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6} sx={{textAlign:"right"}}>
|
||||
<Tooltip title="Ban this artist.">
|
||||
<IconButton color="error">
|
||||
<Block/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Suspend this artist.">
|
||||
<IconButton color="warning">
|
||||
<Close/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Go back a page.">
|
||||
<IconButton onClick={() => router.push("/dashboard/admin/artists")} color="primary">
|
||||
<ArrowBack/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={5}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
Display Name: {artist?.user?.displayName}
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
Email: {artist?.user?.email}
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Button variant="contained" color="primary" fullWidth>Save Changes</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={7}>
|
||||
<TextField size="small" label="Admin Notes" multiline rows={4} fullWidth variant="outlined" value={artist?.userId} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Alert severity={artist?.numberOfBans > 0 ? "error" : "success"}>{artist?.numberOfBans > 0 ? "This user has been banned "+artist?.numberOfBans+" times." : "This user has not been banned before."}</Alert>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Alert severity={artist?.numberOfSuspensions > 0 ? "error" : "success"}>{artist?.numberOfBans > 0 ? "This user has been suspended "+artist?.numberOfSuspensions+" times." : "This user has not been suspended before."}</Alert>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Alert severity="success">This artist has made ${artist?.amountMade}, and we have made ${artist?.feesCollected} in fees.</Alert>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Alert severity={artist?.numberOfRequests > 0 ? "success" : "warning"}>This artist has accepted {artist?.numberOfRequests} requests.</Alert>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Alert severity={artist?.numberOfCompleted > 0 ? "success" : "warning"}>This artist has completed {artist?.numberOfCompleted} requests.</Alert>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// Protected route, checking user authentication client-side.(CSR)
|
||||
export default withPageAuthRequired(AdminArtist);
|
||||
|
||||
|
206
pages/dashboard/admin/requests.tsx
Normal file
206
pages/dashboard/admin/requests.tsx
Normal file
@ -0,0 +1,206 @@
|
||||
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, Stack, 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 {Block, Check, Close, Download, OpenInFull, OpenInNew, Person, Refresh, Star, Upload } 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 ShoppingCartCheckoutIcon from '@mui/icons-material/ShoppingCartCheckout';
|
||||
import { IconButton } from '@mui/material';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import { Card, CardContent } from '@mui/material';
|
||||
import Rating from '@mui/material/Rating';
|
||||
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import { DownloadBox, Magnify, StarOutline } from 'mdi-material-ui';
|
||||
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material';
|
||||
import { Grid } from '@mui/material';
|
||||
import { useRouter } from 'next/router';
|
||||
import { request } from 'http';
|
||||
import { useMediaQuery } from '@mui/material';
|
||||
|
||||
|
||||
export default function AdminRequests() {
|
||||
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm')); // Check if the screen size is small
|
||||
const router = useRouter();
|
||||
let columns = [];
|
||||
if(isSmallScreen){
|
||||
columns = [
|
||||
{ field: 'id', headerName: '', flex: 0.05, sortable: false, filterable: false},
|
||||
{ field: 'message', headerName: 'Message', flex: 0.2, sortable: false, filterable: false},
|
||||
{ field: 'actions', headerName: '', flex: 0.15, sortable: false, filterable: false, renderCell: (params) => {
|
||||
const handleAccept = async () => {
|
||||
var response = await fetch("/api/admin/requests/"+params.row.userId, {method:"PUT"})
|
||||
if(response.ok){
|
||||
var data = await response.json();
|
||||
router.reload();
|
||||
}
|
||||
else{
|
||||
alert("Failed to accept request.")
|
||||
}
|
||||
}
|
||||
const handleDeny = async () => {
|
||||
var response = await fetch("/api/admin/requests/"+params.row.userId, {method:"DELETE"})
|
||||
if(response.ok){
|
||||
var data = await response.json();
|
||||
router.reload();
|
||||
}
|
||||
else{
|
||||
alert("Failed to deny request.")
|
||||
}
|
||||
}
|
||||
if(params.row.accepted){
|
||||
return <>
|
||||
<Tooltip title="Revoke artist access"><IconButton color="error"><Block/></IconButton></Tooltip>
|
||||
<Tooltip title="View artist information"><IconButton onClick={() => router.push("/dashboard/admin/requests/"+params.row.id)} color="info"><Magnify/></IconButton></Tooltip>
|
||||
</>
|
||||
}
|
||||
else{
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="Accept this request and grant artist access."><IconButton onClick={handleAccept} color="success"><Check/></IconButton></Tooltip>
|
||||
<Tooltip title="Decline this request and refuse artist access."><IconButton onClick={handleDeny} color="error"><Close/></IconButton></Tooltip>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}}
|
||||
];
|
||||
}
|
||||
else{
|
||||
columns = [
|
||||
{ field: 'id', headerName: '', flex: 0.05, sortable: false, filterable: false},
|
||||
{ field: 'userId', headerName: 'User ID', flex: 0.25, sortable: false, filterable: false},
|
||||
{ field: 'message', headerName: 'Message', flex: 0.5, sortable: false, filterable: false},
|
||||
{ field: 'requestDate', headerName: 'Request Date', flex: 0.1, sortable: false, filterable: false, type: 'date', valueGetter: (params) => { return new Date(params.row.requestDate); }},
|
||||
{ field: 'accepted', headerName:'Accepted', flex: 0.15, sortable: false, filterable: false, renderCell: (params) => {
|
||||
return (params.row.accepted ? <Chip icon={<Check />} label="Accepted" variant="outlined" color="success" /> : <Chip icon={<Refresh />} label="Pending" variant="outlined" color="info" />)
|
||||
}},
|
||||
{ field: 'actions', headerName: '', flex: 0.15, sortable: false, filterable: false, renderCell: (params) => {
|
||||
const handleAccept = async () => {
|
||||
var response = await fetch("/api/admin/requests/"+params.row.userId, {method:"PUT"})
|
||||
if(response.ok){
|
||||
var data = await response.json();
|
||||
router.reload();
|
||||
}
|
||||
else{
|
||||
alert("Failed to accept request.")
|
||||
}
|
||||
}
|
||||
const handleDeny = async () => {
|
||||
var response = await fetch("/api/admin/requests/"+params.row.userId, {method:"DELETE"})
|
||||
if(response.ok){
|
||||
var data = await response.json();
|
||||
router.reload();
|
||||
}
|
||||
else{
|
||||
alert("Failed to deny request.")
|
||||
}
|
||||
}
|
||||
if(params.row.accepted){
|
||||
return <>
|
||||
<Tooltip title="View request information"><IconButton onClick={() => router.push("/dashboard/admin/requests/"+params.row.id)} color="info"><OpenInNew/></IconButton></Tooltip>
|
||||
<Tooltip title="View artist information"><IconButton onClick={() => router.push("/dashboard/admin/users/"+params.row.id)} color="info"><Person/></IconButton></Tooltip>
|
||||
</>
|
||||
}
|
||||
else{
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="View request information"><IconButton onClick={() => router.push("/dashboard/admin/requests/"+params.row.id)} color="info"><OpenInNew/></IconButton></Tooltip>
|
||||
<Tooltip title="Accept this request and grant artist access."><IconButton onClick={handleAccept} color="success"><Check/></IconButton></Tooltip>
|
||||
<Tooltip title="Decline this request and refuse artist access."><IconButton onClick={handleDeny} color="error"><Close/></IconButton></Tooltip>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}}
|
||||
];
|
||||
}
|
||||
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: 15,
|
||||
});
|
||||
|
||||
|
||||
const getRequests = async () => {
|
||||
setIsLoading(true);
|
||||
const response = await fetch('/api/admin/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/admin/requests/count', {
|
||||
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={{ height: '100%', width: '100%' }}>
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||
<DataGrid
|
||||
rows={requestData}
|
||||
columns={columns}
|
||||
rowCount={rowCountState}
|
||||
loading={isLoading}
|
||||
pageSizeOptions={[15]}
|
||||
paginationModel={paginationModel}
|
||||
paginationMode="server"
|
||||
onPaginationModelChange={setPaginationModel}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
124
pages/dashboard/admin/requests/[requestId].tsx
Normal file
124
pages/dashboard/admin/requests/[requestId].tsx
Normal file
@ -0,0 +1,124 @@
|
||||
import * as React from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'
|
||||
import { Alert, Card, CardContent, Grid, IconButton, TextField, Typography } from '@mui/material';
|
||||
import Button from '@mui/material/Button';
|
||||
import { OpenInNew } from 'mdi-material-ui';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import { ArrowBack } from '@mui/icons-material';
|
||||
|
||||
|
||||
const AdminRequest = () => {
|
||||
const router = useRouter();
|
||||
|
||||
const [request, setRequest] = useState(null);
|
||||
|
||||
|
||||
const getData = async () => {
|
||||
if(router.query.requestId!=null){
|
||||
const response = await fetch("/api/admin/requests/"+router.query.requestId);
|
||||
const data = await response.json();
|
||||
setRequest(data);
|
||||
}
|
||||
}
|
||||
|
||||
const handleAccept = async () => {
|
||||
var response = await fetch("/api/admin/requests/"+router.query.requestId, {method:"PUT"})
|
||||
if(response.ok){
|
||||
var data = await response.json();
|
||||
router.reload();
|
||||
}
|
||||
else{
|
||||
alert("Failed to accept request.")
|
||||
}
|
||||
}
|
||||
const handleDeny = async () => {
|
||||
var response = await fetch("/api/admin/requests/"+router.query.requestId, {method:"DELETE"})
|
||||
if(response.ok){
|
||||
var data = await response.json();
|
||||
router.reload();
|
||||
}
|
||||
else{
|
||||
alert("Failed to deny request.")
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, [router.query.requestId]);
|
||||
|
||||
let formattedTime = ""
|
||||
const date = new Date(request?.requestDate);
|
||||
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
|
||||
return (
|
||||
<>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="h5">{router.query.requestId} - Artist Access Request</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6} sx={{textAlign:"right"}}>
|
||||
<Tooltip title="Go back a page.">
|
||||
<IconButton onClick={() => router.push("/dashboard/admin/requests")} color="primary">
|
||||
<ArrowBack/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Alert severity="info">Submitted on {formattedTime}</Alert>
|
||||
</Grid>
|
||||
{request?.accepted ? (
|
||||
<Grid item xs={12}>
|
||||
<Alert severity="success">This artist access request has been accepted.</Alert>
|
||||
</Grid>
|
||||
):(
|
||||
<Grid item xs={12}>
|
||||
<Alert severity="warning">Pending review from platform administrator.</Alert>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
id="outlined-multiline-static"
|
||||
label="Message"
|
||||
multiline
|
||||
rows={4}
|
||||
fullWidth
|
||||
value={request?.message}
|
||||
disabled>
|
||||
{request?.message}
|
||||
</TextField>
|
||||
</Grid>
|
||||
{request?.accepted ? (
|
||||
<Grid item xs={12} md={12}>
|
||||
<Button fullWidth variant="contained" onClick={handleAccept} color="error">Revoke Artist Access</Button>
|
||||
</Grid>
|
||||
):(
|
||||
<>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Button fullWidth variant="contained" onClick={handleAccept} color="primary">Accept</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Button fullWidth variant="contained" onClick={handleDeny} color="secondary">Reject</Button>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// Protected route, checking user authentication client-side.(CSR)
|
||||
export default withPageAuthRequired(AdminRequest);
|
||||
|
||||
|
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