Compare commits

...

15 Commits
0.5.1 ... main

Author SHA1 Message Date
01cc7eb197 Revert "dockerfile"
This reverts commit 2d4663ef7416ea2f3efe808f0cfca9a0557f0dc3.
2024-05-21 22:35:19 -04:00
2d4663ef74 dockerfile 2024-05-21 22:35:13 -04:00
Damien Ostler
0807d6d11d fix: removed logo that is broken 2024-03-17 06:56:35 -04:00
Damien Ostler
2a405067d8 feat: added pages for viewing artist access requests, users, and artists in the admin menus 2024-03-17 06:47:37 -04:00
Damien Ostler
23ea8eed79 fix: admin menus dont show up for non admins now 2024-03-03 16:23:40 -05:00
Damien Ostler
8569290c0e chore: cleaned up the naming of components, apis, and pgaes. 2024-03-03 16:19:47 -05:00
Damien Ostler
5a2f43768d feat: admin list pages and apis 2024-03-03 16:03:22 -05:00
Damien Ostler
ff465278ad fix: filtering and sorting disabled now 2024-03-03 14:11:43 -05:00
Damien Ostler
a63d7f35b8 fix: upload button enabled when not paid 2024-03-02 01:23:02 -05:00
Damien Ostler
93d4518500 feat: refactoring + assets and reference images and reviews 2024-03-02 00:51:43 -05:00
Damien Ostler
d52018f7eb removed login override 2024-02-28 21:28:30 -05:00
Damien Ostler
aac4ec902f feat: rating/reviews 2024-02-27 21:37:43 -05:00
Damien Ostler
238477665d feat: alot of shit i forgot to push lol woops 2024-02-25 18:34:51 -05:00
Damien Ostler
b9aed8f3bb fix: name not being returned 2024-02-18 07:23:34 -05:00
Damien Ostler
565cb5dffb feat: shop builder 2024-02-18 06:59:55 -05:00
127 changed files with 5098 additions and 4965 deletions

View File

@ -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

View File

@ -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
View 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

View File

@ -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

View File

@ -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

View File

@ -1,82 +0,0 @@
import * as React from 'react';
import { ImageList, Box, Button, CircularProgress } from '@mui/material';
import { useEffect, useState } from "react";
import EditableArtistPortfolioImage from './editableArtistPortfolioImage';
import FileOpenIcon from '@mui/icons-material/FileOpen';
import { Grid } from '@mui/material';
const EditableArtistPortfolio = ({ artistId }) => {
const [portfolioData, setPortfolioData] = useState([]);
const [loading, setLoading] = useState(true); // State for loading indicator
useEffect(() => {
getData();
}, []);
const getData = async () => {
const response = await fetch('/api/discovery/artist/' + artistId + '/portfolio');
const data = await response.json();
setPortfolioData(data);
setLoading(false);
}
function handlePortfolioUploadImageChange(event) {
const file = event.target.files[0];
const formData = new FormData();
formData.append('newImage', file);
fetch('/api/artist/portfolio', {
method: 'POST',
body: formData // Don't set Content-Type, FormData will handle it
})
.then(response => response.json())
.then(data => {
getData();
})
.catch(error => {
console.error('Error uploading file:', error);
// Handle error appropriately
});
}
return (
(loading) ? (
<Box sx={{ textAlign: "center", paddingTop: 20 }}>
<CircularProgress sx={{ paddingTop: 5 }} />
</Box>
) :
(
<Grid container spacing={2} sm={12}>
<Grid item xs={12} sm={12} sx={{ textAlign: "center" }}>
<input
id="portfolioUploadInput"
style={{ display: 'none' }}
accept="image/*"
type="file"
onChange={handlePortfolioUploadImageChange}
/>
<label htmlFor="portfolioUploadInput">
<Button
fullWidth
variant='outlined'
component="span"
size="small"
sx={{width:"100%"}}
startIcon={<FileOpenIcon />}
>
{(portfolioData.length > 0 ? "Upload Another Portfolio Image" : "Upload Your First Portfolio Image")}
</Button>
</label>
</Grid>
<Grid item xs={12} sm={12}>
<ImageList cols={2} rowHeight={200} sx={{ height: 400, width:"100%" }}>
{portfolioData.map((item) => (
<EditableArtistPortfolioImage artistId={artistId} itemId={item.id} reload={getData}/>
))}
</ImageList>
</Grid>
</Grid>
)
)
}
export default EditableArtistPortfolio

View File

@ -1,48 +0,0 @@
import * as React from 'react';
import ImageList from '@mui/material/ImageList';
import ImageListItem from '@mui/material/ImageListItem';
import { useEffect, useState } from "react";
import DeleteIcon from '@mui/icons-material/Delete';
import { CircularProgress, ImageListItemBar } from '@mui/material';
import { IconButton } from '@mui/material';
const EditableArtistPortfolioImage = ({artistId,itemId,reload}) => {
const [loaded, setLoaded] = useState(false);
const [deleting, setDeleting] = useState(false);
const handleImageLoaded = () => {
setLoaded(true);
};
const deleteButton = () => {
setDeleting(true);
fetch('/api/artist/portfolio/'+itemId+"/delete", {
method: 'DELETE'
}).then(response => {
reload().then(data => {
})
})
}
return (
<ImageListItem key={itemId } sx={{maxWidth:300, maxHeight:300, overflow:"hidden"}}>
<img
srcSet={process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${artistId}/Portfolio/${itemId}`}
src={process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${artistId}/Portfolio/${itemId}`}
alt={itemId}
loading="lazy"
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor:'grey' }}
onLoad={handleImageLoaded}
/>
<ImageListItemBar
actionIcon={
<IconButton onClick={deleteButton} color="error" >
<DeleteIcon />
</IconButton>
}>
</ImageListItemBar>
</ImageListItem>)
}
export default EditableArtistPortfolioImage

View File

@ -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;

View File

@ -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;

View File

@ -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)
}}
/>
)
}

View File

@ -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="primary" fullWidth>View More</Button>);
}},
];
const rows = [
{ id: 1, artist:'Neroshi', status: 'Pending'},
];
export default function Orders() {
return (
<div style={{ height: 400, width: '100%' }}>
<DataGrid
rows={rows}
columns={columns}
initialState={{
pagination: {
paginationModel: { page: 0, pageSize: 5 },
},
}}
pageSizeOptions={[5, 10]}
/>
</div>
);
}

View File

@ -1,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>

View 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>
);
}

View 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;

View 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;

View File

@ -0,0 +1,96 @@
import * as React from 'react';
import { useEffect, useState } from "react";
import { Grid, ImageList, Box, Tooltip, CircularProgress, Slider, IconButton } from '@mui/material';
import { FileUpload } from '@mui/icons-material';
import EditableArtistPortfolioImage from './editablePortfolioImage';
const EditableArtistPortfolio = ({ artistId }) => {
const [portfolioData, setPortfolioData] = useState([]);
const [columns, setColumns] = useState(2);
const [loading, setLoading] = useState(true); // State for loading indicator
useEffect(() => {
getData();
}, []);
const handleColumns = (event, value)=>{
setColumns(value);
}
const getData = async () => {
const response = await fetch('/api/discovery/artist/' + artistId + '/portfolio');
const data = await response.json();
setPortfolioData(data);
setLoading(false);
}
function handlePortfolioUploadImageChange(event) {
const file = event.target.files[0];
const formData = new FormData();
formData.append('newImage', file);
fetch('/api/artist/portfolio', {
method: 'POST',
body: formData // Don't set Content-Type, FormData will handle it
})
.then(response => response.json())
.then(data => {
getData();
})
.catch(error => {
console.error('Error uploading file:', error);
// Handle error appropriately
});
}
return (
(loading) ? (
<Box sx={{ textAlign: "center", paddingTop: 20 }}>
<CircularProgress sx={{ paddingTop: 5 }} />
</Box>
) :
(
<Grid container spacing={2} sm={12}>
<Grid item xs={12} sm={1} sx={{ textAlign: "center" }}>
<input
id="portfolioUploadInput"
style={{ display: 'none' }}
accept="image/*"
type="file"
onChange={handlePortfolioUploadImageChange}
/>
<label htmlFor="portfolioUploadInput">
<Tooltip arrow title="Upload Image To Portfolio">
<IconButton color="primary" component="span">
<FileUpload sx={{fontSize:"2rem"}}/>
</IconButton>
</Tooltip>
</label>
</Grid>
<Grid item xs={12} sm={11} sx={{ textAlign: "center" }}>
<Tooltip arrow title="Amount of columns">
<Slider
defaultValue={columns}
aria-labelledby="discrete-slider"
valueLabelDisplay="auto"
onChange={handleColumns}
step={1}
marks
min={1}
max={5}/>
</Tooltip>
</Grid>
<Grid item xs={12} sm={12} sx={{maxHeight:"45rem",overflowY:"scroll"}}>
<ImageList variant='masonry' cols={columns} sx={{ width:"100%" }}>
{portfolioData.map((item) => (
<EditableArtistPortfolioImage artistId={artistId} itemId={item.id} reload={getData}/>
))}
</ImageList>
</Grid>
</Grid>
)
)
}
export default EditableArtistPortfolio

View 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;

View File

@ -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);
@ -22,20 +22,21 @@ const ArtistPortfolio = ({masonry,columns,artistId}) => {
<Typography variant="h4" sx={{textAlign:"center"}}>
Loading
</Typography>
<CircularProgress sx={{paddingTop:5}} />
<Box sx={{paddingTop:"2%"}}/>
<CircularProgress />
</Box>
) :
(
(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} >
<ImageList cols={columns} sx={{ width:"100%" }}>
{portfolioData.map((item) => (
<ArtistPortfolioImage artistId={artistId} itemId={item.id} />
<ArtistPortfolioImage artistId={profileId} itemId={item.id} />
))}
</ImageList>
)

View 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;

View 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>
);
}

View File

@ -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

View 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;

View 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;

View 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>
);
}

View File

@ -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

View File

@ -1,5 +1,5 @@
// ** React Imports
import { useState, SyntheticEvent, Fragment } from 'react'
import { useState, SyntheticEvent, Fragment, useEffect } from 'react'
// ** Next Import
import { useRouter } from 'next/router'
@ -37,6 +37,17 @@ const BadgeContentSpan = styled('span')(({ theme }) => ({
const UserDropdown = () => {
const { user, isLoading } = useUser();
const [appUser, setAppUser] = useState(null);
useEffect(() => {
getData()
}, []);
const getData = async () => {
var userResponse = await fetch('/api/me');
var user = await userResponse.json();
setAppUser(user);
}
// ** States
const [anchorEl, setAnchorEl] = useState<Element | null>(null)
@ -69,7 +80,7 @@ const UserDropdown = () => {
}
return (
(!isLoading && user) ? (
(!isLoading && user && appUser) ? (
<Fragment>
<Badge
overlap='circular'
@ -100,10 +111,10 @@ const UserDropdown = () => {
badgeContent={<BadgeContentSpan />}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
>
<Avatar alt={user.nickname} src={user.picture} sx={{ width: '2.5rem', height: '2.5rem' }} />
<Avatar alt={appUser["displayName"]} src={user.picture} sx={{ width: '2.5rem', height: '2.5rem' }} />
</Badge>
<Box sx={{ display: 'flex', marginLeft: 3, alignItems: 'flex-start', flexDirection: 'column' }}>
<Typography sx={{ fontWeight: 600 }}>{user.nickname}</Typography>
<Typography sx={{ fontWeight: 600 }}>{appUser["displayName"]}</Typography>
<Typography variant='body2' sx={{ fontSize: '0.8rem', color: 'text.disabled' }}>
Welcome back!
</Typography>
@ -111,43 +122,12 @@ const UserDropdown = () => {
</Box>
</Box>
<Divider sx={{ mt: 0, mb: 1 }} />
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
<Box sx={styles}>
<AccountOutline sx={{ marginRight: 2 }} />
Profile
</Box>
</MenuItem>
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
<Box sx={styles}>
<EmailOutline sx={{ marginRight: 2 }} />
Inbox
</Box>
</MenuItem>
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
<Box sx={styles}>
<MessageOutline sx={{ marginRight: 2 }} />
Chat
</Box>
</MenuItem>
<Divider />
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
<MenuItem sx={{ p: 0 }} onClick={() => router.push("/dashboard/settings")}>
<Box sx={styles}>
<CogOutline sx={{ marginRight: 2 }} />
Settings
</Box>
</MenuItem>
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
<Box sx={styles}>
<CurrencyUsd sx={{ marginRight: 2 }} />
Pricing
</Box>
</MenuItem>
<MenuItem sx={{ p: 0 }} onClick={() => handleDropdownClose()}>
<Box sx={styles}>
<HelpCircleOutline sx={{ marginRight: 2 }} />
FAQ
</Box>
</MenuItem>
<Divider />
<MenuItem sx={{ py: 2 }} onClick={() => handleDropdownClose('/api/auth/logout')}>
<LogoutVariant sx={{ marginRight: 2, fontSize: '1.375rem', color: 'text.secondary' }} />

View File

@ -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

View File

@ -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>

View File

@ -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 ? (
@ -50,26 +61,15 @@ const AppBarContent = (props: Props) => {
<Menu />
</IconButton>
) : null}
<TextField
size='small'
sx={{ '& .MuiOutlinedInput-root': { borderRadius: 4 } }}
InputProps={{
startAdornment: (
<InputAdornment position='start'>
<Magnify fontSize='small' />
</InputAdornment>
)
}}
/>
</Box>
<Box className='actions-right' sx={{ display: 'flex', alignItems: 'center' }}>
<ModeToggler settings={settings} saveSettings={saveSettings} />
<NovuProvider subscriberId={'on-boarding-subscriber-id-123'} applicationIdentifier={'9SKjzgN_odAF'}>
<PopoverNotificationCenter colorScheme={'light'}>
{(profileData ? (
<NovuProvider subscriberId={profileData["id"]} applicationIdentifier={'9SKjzgN_odAF'}>
<PopoverNotificationCenter colorScheme={'dark'}>
{({ unseenCount }) => <NotificationBell unseenCount={unseenCount} />}
</PopoverNotificationCenter>
</NovuProvider>
):null)}
<UserDropdown />
</Box>
</Box>

View File

@ -3,80 +3,129 @@ import Login from 'mdi-material-ui/Login'
import Table from 'mdi-material-ui/Table'
import CubeOutline from 'mdi-material-ui/CubeOutline'
import HomeOutline from 'mdi-material-ui/HomeOutline'
import FormatLetterCase from 'mdi-material-ui/FormatLetterCase'
import AccountCogOutline from 'mdi-material-ui/AccountCogOutline'
import CreditCardOutline from 'mdi-material-ui/CreditCardOutline'
import AccountPlusOutline from 'mdi-material-ui/AccountPlusOutline'
import AlertCircleOutline from 'mdi-material-ui/AlertCircleOutline'
import GoogleCirclesExtended from 'mdi-material-ui/GoogleCirclesExtended'
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 [
{
sectionTitle: 'General'
},
var result = [
{
title: 'Dashboard',
icon: HomeOutline,
path: '/dashboard'
},
{
sectionTitle: 'General'
},
{
title: 'Account Settings',
icon: Settings,
path: '/artist/settings'
path: '/dashboard/settings'
},
{
title: 'Your Requests',
icon: ListIcon,
path: '/dashboard/requests'
}
];
if (isAdmin) {
result.push(
{
sectionTitle: 'Admin'
},
{
title: 'Manage Artist Access',
icon: LockPerson,
path: '/dashboard/admin/requests'
},
{
title: 'Manage Users',
icon: People,
path: '/dashboard/admin/users'
},
{
title: 'Manage Artists',
icon: PeopleOutline,
path: '/dashboard/admin/artists'
},
);
}
if (isStripeOnboarded) {
result.push(
{
sectionTitle: 'Artist'
},
{
title: 'Payout Portal',
title: 'Request Reviews',
icon: StarOutline,
path: '/dashboard/artist/reviews'
},
{
title: 'Incoming Requests',
icon: ListIcon,
path: '/dashboard/artist/requests'
},
{
title: 'Payments/Payouts',
icon: BankTransfer,
path: '/payoutportal'
path: '/dashboard/artist/payout'
},
{
title: 'Artist Settings',
icon: Settings,
path: '/dashboard/artist/artistsettings'
},
{
title: 'Page Settings',
icon: DocumentScanner,
icon: WebAsset,
path: '/dashboard/artist/pagesettings'
},
{
title: 'Preview Page',
icon: FileOpen,
path: '/artist/pagesettings'
}
]
}
else{
return [
{
sectionTitle: 'General'
},
{
title: 'Dashboard',
icon: HomeOutline,
path: '/dashboard'
}
]
title: 'Your Page',
icon: OpenInBrowser,
path: '/box/' + (userData ? userData["displayName"] : "")
}
);
}
export default navigation
return result;
}
export default navigation;

109
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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

View File

@ -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;

View File

@ -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();

View 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);
});

View 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);
});

View 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);
});

View 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);
});

View 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);
});

View 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
View 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({})
});

View 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);
});

View 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

View 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
View 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);
});

View 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);
});

View 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);
});

View 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);
});

View 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);
});

View 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);
});

View 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);
});

View File

@ -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);

View 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);
});

View File

@ -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);
});

View File

@ -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
View 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);
}
});

View 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);
}
});

View File

@ -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}`,

View File

@ -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}`

View File

@ -2,7 +2,21 @@ 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', {
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);
}
else{
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist', {
headers: {
"Authorization": `Bearer ${accessToken}`
}
@ -10,5 +24,6 @@ export default withApiAuthRequired(async function sellerProfile(req, res) {
let result = await response.json();
res.status(200).json(result);
}
});

View File

@ -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}`
},

View 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);
});

View 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);
});

View 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);
});

View 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);
});

View 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);
});

View 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);
});

View 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);
});

View 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);
});

View 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' });
}
});
});

View 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);
});

View 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/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);
});

View 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);
});

View 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);
});

View 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);
}
});

View 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);
}

View 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' });
}
}

View File

@ -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');

View File

@ -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) {

View 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);
}

View 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);
}

View File

@ -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');

34
pages/api/me.tsx Normal file
View File

@ -0,0 +1,34 @@
import { useRouter } from 'next/router'
import { withApiAuthRequired } from "@auth0/nextjs-auth0";
import { getAccessToken } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
if(req.method !== 'GET') {
////console.log(req.body)
const { accessToken } = await getAccessToken(req, res);
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/User', {
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": "application/json"
},
method: "PUT",
body: req.body
});
let result = await response.json();
res.status(200).json(result);
}
else{
const { accessToken } = await getAccessToken(req, res);
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/User', {
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": "application/json"
}
});
let result = await response.json();
res.status(200).json(result);
}
});

View 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
View 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);
});

View 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);
});

View 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);
});

View 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);
});

View 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' });
}
});
});

View 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);
});

View 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);
});

View 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);
});

View 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);
});

View File

@ -1,108 +0,0 @@
import Layout from "../../components/OLd/layout";
import { useUser } from "@auth0/nextjs-auth0/client";
import { Box, Grid, Card, CardContent, Typography, List, Button, CircularProgress, Tooltip } from "@mui/material";
import { useState, useEffect } from "react";
import { useRouter } from 'next/router'
import ArtistPortfolio from "../../components/artistPortfolio";
const SellerProfile = () => {
const { user, isLoading } = useUser();
const router = useRouter()
const { id } = router.query
const [sellerData, setSellerData] = useState([]);
const [loading, setLoading] = useState(true); // State for loading indicator
useEffect(() => {
const getData = async () => {
if(id){
const response = await fetch('/api/discovery/artist/'+id);
const data = await response.json();
setSellerData(data);
setLoading(false); // Once data is fetched, set loading to false
}
}
getData();
}, [id]);
const [value, setValue] = useState(0);
return (
<Layout user={user} loading={isLoading}>
{loading ? ( // Render loading indicator if loading is true
<Box sx={{textAlign:"center", paddingTop:20}}>
<Typography variant="h4" sx={{textAlign:"center"}}>
Loading
</Typography>
<Box sx={{ paddingTop: 5 }} />
<CircularProgress />
</Box>
) : (
<Grid container spacing={2} sx={{padding:4}}>
<Grid container sx={{textAlign:"center"}}>
<Grid item xs={12} sm={2} sx={{textAlign:"center"}}>
<Button color="primary" variant="contained" href="../">
Back
</Button>
</Grid>
<Grid item xs={12} sm={8} sx={{textAlign:"center"}}>
<Typography variant="h4">
{sellerData["name"]}
</Typography>
</Grid>
<Grid item xs={12} sm={2} sx={{textAlign:"center"}}>
</Grid>
</Grid>
<Grid item xs={12} sm={6}>
<Card sx={{height:250, overflowY: 'scroll'}}>
<CardContent>
<Typography variant="h5" sx={{textAlign:"center"}}>
Biography
</Typography>
<Typography sx={{paddingTop:2, textAlign:"center"}}>
{sellerData["biography"]}
</Typography>
</CardContent>
</Card>
</Grid>
<Grid item xs={12} md={6}>
<Card sx={{height:250, overflowY: 'scroll'}}>
<CardContent sx={{textAlign:"center"}}>
<Grid item xs={12} md={12}>
<Typography variant="h5">
Social Media
</Typography>
<List
sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
aria-label="contacts"
>
</List>
</Grid>
<Grid item xs={12} md={12}>
</Grid>
</CardContent>
</Card>
</Grid>
<Grid item xs={12} sm={12} sx={{textAlign:"center"}} >
{user ? (
<Button size="large" color="secondary" variant="contained" href={"/artist/"+id+"/request"}>
Request Order
</Button>
) : (
<Tooltip title="Log in order to place a request.">
<span>
<Button size="large" color="secondary" variant="contained" disabled>
Submit Request
</Button>
</span>
</Tooltip>
)}
</Grid>
<Grid item xs={12} sm={12}>
<ArtistPortfolio artistId={id} />
</Grid>
</Grid>
)}
</Layout>
);
};
export default SellerProfile;

View File

@ -1,118 +0,0 @@
import Layout from "../../../components/OLd/layout";
import { useUser } from "@auth0/nextjs-auth0/client";
import { Box, Grid, Typography, Button, CircularProgress, TextField} from "@mui/material";
import { useState, useEffect } from "react";
import { useRouter } from 'next/router'
import CurrencyTextField from '@lupus-ai/mui-currency-textfield'
interface TabPanelProps {
children?: React.ReactNode;
index: number;
value: number;
}
const SellerProfile = () => {
const { user, isLoading } = useUser();
const router = useRouter()
const { id } = router.query
const [sellerData, setSellerData] = useState([]);
const [loading, setLoading] = useState(true); // State for loading indicator
useEffect(() => {
const getData = async () => {
if(id){
const response = await fetch('/api/discovery/artist/'+id);
const data = await response.json();
setSellerData(data);
setLoading(false); // Once data is fetched, set loading to false
}
}
getData();
}, [id]);
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
setValue(newValue);
};
const [value, setValue] = useState(0);
return (
<Layout user={user} loading={isLoading}>
{loading ? ( // Render loading indicator if loading is true
<Box sx={{textAlign:"center", paddingTop:20}}>
<Typography variant="h4" sx={{textAlign:"center"}}>
Loading
</Typography>
<Box sx={{ paddingTop: 5 }} />
<CircularProgress />
</Box>
) : (
<Grid container spacing={2} sx={{padding:4}}>
<Grid container sx={{textAlign:"center"}}>
<Grid item xs={12} sm={2} sx={{textAlign:"center"}}>
<Button color="primary" variant="contained" href={"../"+id}>
Back
</Button>
</Grid>
<Grid item xs={12} sm={8} sx={{textAlign:"center"}}>
<Typography variant="h4">
New Request
</Typography>
</Grid>
<Grid item xs={12} sm={2} sx={{textAlign:"center"}}>
</Grid>
</Grid>
<Grid container item xs={12} sm={12} sx={{textAlign:"center"}} >
{user ? (
<>
<Grid item xs={12} sm={12} sx={{textAlign:"center"}} >
<TextField fullWidth disabled id="fo" label="Artist" variant="outlined" value={sellerData["name"]}/>
<Box sx={{padding:2}} />
<TextField id="outlined-multiline-static" label="Request Details" fullWidth multiline rows={4} defaultValue="" placeholder="Put the details of your request. Links to reference images. Descriptions of what you want. Things like that."/>
<Box sx={{padding:2}} />
</Grid>
<Grid item xs={12} sm={12} sx={{textAlign:"center"}} >
<Button>
<input type="file" multiple />
</Button>
</Grid>
<Box sx={{padding:2}} />
<Grid item xs={12} sm={12} sx={{textAlign:"center"}} >
<CurrencyTextField
label="Offer Amount"
variant="standard"
value={value}
currencySymbol="USD "
//minimumValue="0"
outputFormat="string"
decimalCharacter="."
digitGroupSeparator=","
onChange={(event, value)=> setValue(value)}/>
</Grid>
<Box sx={{padding:2}} />
<Grid item xs={12} sm={12} sx={{textAlign:"center"}} >
<Button color="secondary" variant="contained" >
Submit Request
</Button>
</Grid>
</>
) : (
<>
<Typography>
Please login to place a request.
</Typography>
<Button color="primary" variant="contained" href="/api/auth/login">
Login
</Button>
</>
)}
</Grid>
</Grid>
)}
</Layout>
);
};
export default SellerProfile;

257
pages/box/[artistName].tsx Normal file
View 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);

View File

@ -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

View 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>
);
}

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