mirror of
https://github.com/D4M13N-D3V/comissions-app-ui.git
synced 2025-03-13 07:45:07 +00:00
feat: alot of shit i forgot to push lol woops
This commit is contained in:
parent
b9aed8f3bb
commit
238477665d
@ -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
|
||||
|
49
components/ArtistRequest.tsx
Normal file
49
components/ArtistRequest.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import * as React from 'react';
|
||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid';
|
||||
import { Button } from '@mui/material';
|
||||
import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
||||
import { Grid, Typography } from "@mui/material";
|
||||
import Card from "@mui/material/Card";
|
||||
import CardContent from "@mui/material/CardContent";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
|
||||
|
||||
export default function ArtistRequest({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>
|
||||
);
|
||||
}
|
178
components/ArtistStats.tsx
Normal file
178
components/ArtistStats.tsx
Normal file
@ -0,0 +1,178 @@
|
||||
// ** React Imports
|
||||
import { ReactElement } from 'react'
|
||||
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box'
|
||||
import Grid from '@mui/material/Grid'
|
||||
import Card from '@mui/material/Card'
|
||||
import Avatar from '@mui/material/Avatar'
|
||||
import CardHeader from '@mui/material/CardHeader'
|
||||
import IconButton from '@mui/material/IconButton'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import CardContent from '@mui/material/CardContent'
|
||||
|
||||
// ** Icons Imports
|
||||
import TrendingUp from 'mdi-material-ui/TrendingUp'
|
||||
import CurrencyUsd from 'mdi-material-ui/CurrencyUsd'
|
||||
import DotsVertical from 'mdi-material-ui/DotsVertical'
|
||||
import CellphoneLink from 'mdi-material-ui/CellphoneLink'
|
||||
import AccountOutline from 'mdi-material-ui/AccountOutline'
|
||||
import CompareArrowsIcon from '@mui/icons-material/CompareArrows';
|
||||
|
||||
// ** Types
|
||||
import { ThemeColor } from '../core/layouts/types'
|
||||
import { Person } from '@mui/icons-material'
|
||||
|
||||
interface DataType {
|
||||
stats: string
|
||||
title: string
|
||||
color: ThemeColor
|
||||
icon: ReactElement
|
||||
}
|
||||
|
||||
const salesData: DataType[] = [
|
||||
{
|
||||
stats: '0',
|
||||
title: 'Pending',
|
||||
color: 'secondary',
|
||||
icon: <Person sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '0',
|
||||
title: 'Accepted',
|
||||
color: 'info',
|
||||
icon: <CompareArrowsIcon sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '0',
|
||||
color: 'error',
|
||||
title: 'Declined',
|
||||
icon: <CompareArrowsIcon sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '0',
|
||||
color: 'success',
|
||||
title: 'Completed',
|
||||
icon: <CurrencyUsd sx={{ fontSize: '1.75rem' }} />
|
||||
}
|
||||
]
|
||||
|
||||
const ArtistStats = ({profileData, stats}) => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
title='Artist Statistics'
|
||||
subheader={
|
||||
<>
|
||||
<Typography variant='body2'>
|
||||
<Box component='span' sx={{ fontWeight: 600, color: 'text.primary' }}>
|
||||
You have earned ${stats["revenue"]}
|
||||
</Box>{' '}
|
||||
😎 from {stats["paidRequests"]} requests.
|
||||
</Typography>
|
||||
<Typography variant='body2'>
|
||||
You have <b>{stats["pendingRequests"]}</b> pending requests.
|
||||
</Typography>
|
||||
</>
|
||||
}
|
||||
titleTypographyProps={{
|
||||
sx: {
|
||||
mb: 2.5,
|
||||
lineHeight: '2rem !important',
|
||||
letterSpacing: '0.15px !important'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<CardContent sx={{ pt: theme => `${theme.spacing(3)} !important` }}>
|
||||
<Grid container spacing={[5, 0]}>
|
||||
<Grid item xs={12} 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={12} 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={12} 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={12} 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
|
@ -23,12 +23,12 @@ import { useEffect, useState } from "react";
|
||||
import { IconButton } from '@mui/material';
|
||||
|
||||
const Artist = ({user, artistId}) => {
|
||||
const [sellerData, setSellerData] = useState([]);
|
||||
const [sellerData, setArtistData] = useState([]);
|
||||
useEffect(() => {
|
||||
const getData = async () => {
|
||||
const response = await fetch('/api/discovery/artist/'+artistId);
|
||||
const data = await response.json();
|
||||
setSellerData(data);
|
||||
setArtistData(data);
|
||||
}
|
||||
getData();
|
||||
}, []);
|
||||
|
@ -6,12 +6,12 @@ import Box from '@mui/material/Box';
|
||||
|
||||
|
||||
const ArtistDashboardRequest = () => {
|
||||
const [sellerRequestData, setSellerRequestData] = useState(null);
|
||||
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();
|
||||
|
@ -5,10 +5,11 @@ import ArtistPortfolioImage from './artistPortfolioImage';
|
||||
|
||||
const ArtistPortfolio = ({masonry,columns,artistId}) => {
|
||||
const [portfolioData, setPortfolioData] = useState([]);
|
||||
const [profileId, setArtistId] = useState(artistId)
|
||||
const [loading, setLoading] = useState(true); // State for loading indicator
|
||||
useEffect(() => {
|
||||
const getData = async () => {
|
||||
const response = await fetch('/api/discovery/artist/'+artistId+'/portfolio');
|
||||
const response = await fetch('/api/discovery/artist/'+profileId+'/portfolio');
|
||||
const data = await response.json();
|
||||
setPortfolioData(data);
|
||||
setLoading(false);
|
||||
@ -28,15 +29,15 @@ const ArtistPortfolio = ({masonry,columns,artistId}) => {
|
||||
) :
|
||||
(
|
||||
(masonry) ? (
|
||||
<ImageList variant="masonry" gap={8} cols={columns} sx={{overflowY:"scroll", maxWidth:"100%"}} >
|
||||
<ImageList variant='masonry' cols={columns} sx={{ width:"100%" }}>
|
||||
{portfolioData.map((item) => (
|
||||
<ArtistPortfolioImage artistId={artistId} itemId={item.id} />
|
||||
<ArtistPortfolioImage artistId={profileId} itemId={item.id} />
|
||||
))}
|
||||
</ImageList>
|
||||
):(
|
||||
<ImageList gap={8} cols={columns} >
|
||||
{portfolioData.map((item) => (
|
||||
<ArtistPortfolioImage artistId={artistId} itemId={item.id} />
|
||||
<ImageList cols={columns} sx={{ width:"100%" }}>
|
||||
{portfolioData.map((item) => (
|
||||
<ArtistPortfolioImage artistId={profileId} itemId={item.id} />
|
||||
))}
|
||||
</ImageList>
|
||||
)
|
||||
|
@ -16,8 +16,8 @@ const ArtistPortfolioImage = ({artistId,itemId}) => {
|
||||
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}`}
|
||||
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' }}
|
||||
|
@ -27,10 +27,10 @@ const EditableArtistPortfolioImage = ({artistId,itemId,reload}) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<ImageListItem key={itemId } >
|
||||
<ImageListItem key={itemId }>
|
||||
<img
|
||||
srcSet={process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${artistId}/Portfolio/${itemId}`}
|
||||
src={process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${artistId}/Portfolio/${itemId}`}
|
||||
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' }}
|
||||
|
@ -22,7 +22,7 @@ type HeaderProps = {
|
||||
};
|
||||
|
||||
|
||||
const settings = ['Seller Dashboard', 'Account', 'Dashboard', 'Logout'];
|
||||
const settings = ['Artist Dashboard', 'Account', 'Dashboard', 'Logout'];
|
||||
|
||||
function ResponsiveAppBar() {
|
||||
const [anchorElNav, setAnchorElNav] = React.useState<null | HTMLElement>(null);
|
||||
|
@ -36,12 +36,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 +55,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 +68,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 +123,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>
|
||||
|
@ -1,33 +1,141 @@
|
||||
import * as React from 'react';
|
||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid';
|
||||
import { Button } from '@mui/material';
|
||||
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';
|
||||
|
||||
const columns: GridColDef[] = [
|
||||
{ field: 'id', headerName: 'ID', width: 70 },
|
||||
{ field: 'artist', headerName: 'Artist', width: 130 },
|
||||
{ field: 'status', headerName: 'Status', width: 130 },
|
||||
{ field: 'action', headerName: 'Action', width: 180, renderCell: (params) => {
|
||||
return (<Button variant="outlined" color="secondary" fullWidth>View More</Button>);
|
||||
}},
|
||||
];
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const rows = [
|
||||
{ id: 1, artist:'Neroshi', status: 'Pending'},
|
||||
];
|
||||
|
||||
export default function Orders() {
|
||||
export default function ServerPaginationGrid() {
|
||||
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: 'Amount', flex: 0.1, renderCell: (params) => {
|
||||
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
|
||||
}},
|
||||
{ field: 'requestDate', headerName: 'Request Date', flex:0.15,
|
||||
renderCell: (params) =>{
|
||||
|
||||
let formattedTime = ""
|
||||
const date = new Date(params.row.requestDate);
|
||||
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
|
||||
return <DateField
|
||||
size='small'
|
||||
disabled
|
||||
defaultValue={dayjs(params.row.requestDate)}
|
||||
format="LL"
|
||||
/>
|
||||
} }
|
||||
];
|
||||
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={{ height: 400, width: '100%' }}>
|
||||
<div style={{ width: '100%' }}>
|
||||
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||
<DataGrid
|
||||
rows={rows}
|
||||
minHeight={"500px"}
|
||||
rows={requestData}
|
||||
columns={columns}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: { page: 0, pageSize: 5 },
|
||||
},
|
||||
}}
|
||||
pageSizeOptions={[5, 10]}
|
||||
rowCount={rowCountState}
|
||||
loading={isLoading}
|
||||
pageSizeOptions={[5]}
|
||||
paginationModel={paginationModel}
|
||||
paginationMode="server"
|
||||
onPaginationModelChange={setPaginationModel}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
// ** React Imports
|
||||
import { ReactElement } from 'react'
|
||||
|
||||
// ** MUI Imports
|
||||
import Box from '@mui/material/Box'
|
||||
import Grid from '@mui/material/Grid'
|
||||
import Card from '@mui/material/Card'
|
||||
import Avatar from '@mui/material/Avatar'
|
||||
import CardHeader from '@mui/material/CardHeader'
|
||||
import IconButton from '@mui/material/IconButton'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import CardContent from '@mui/material/CardContent'
|
||||
|
||||
// ** Icons Imports
|
||||
import TrendingUp from 'mdi-material-ui/TrendingUp'
|
||||
import CurrencyUsd from 'mdi-material-ui/CurrencyUsd'
|
||||
import DotsVertical from 'mdi-material-ui/DotsVertical'
|
||||
import CellphoneLink from 'mdi-material-ui/CellphoneLink'
|
||||
import AccountOutline from 'mdi-material-ui/AccountOutline'
|
||||
import CompareArrowsIcon from '@mui/icons-material/CompareArrows';
|
||||
|
||||
// ** Types
|
||||
import { ThemeColor } from '../core/layouts/types'
|
||||
import { Person } from '@mui/icons-material'
|
||||
|
||||
interface DataType {
|
||||
stats: string
|
||||
title: string
|
||||
color: ThemeColor
|
||||
icon: ReactElement
|
||||
}
|
||||
|
||||
const salesData: DataType[] = [
|
||||
{
|
||||
stats: '0',
|
||||
title: 'Customers',
|
||||
color: 'primary',
|
||||
icon: <Person sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '0',
|
||||
title: 'Accepted',
|
||||
color: 'success',
|
||||
icon: <CompareArrowsIcon sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '0',
|
||||
color: 'warning',
|
||||
title: 'Denied',
|
||||
icon: <CompareArrowsIcon sx={{ fontSize: '1.75rem' }} />
|
||||
},
|
||||
{
|
||||
stats: '$0.00',
|
||||
color: 'info',
|
||||
title: 'Revenue',
|
||||
icon: <CurrencyUsd sx={{ fontSize: '1.75rem' }} />
|
||||
}
|
||||
]
|
||||
|
||||
const renderStats = () => {
|
||||
return salesData.map((item: DataType, index: number) => (
|
||||
<Grid item xs={12} sm={3} key={index}>
|
||||
<Box key={index} sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Avatar
|
||||
variant='rounded'
|
||||
sx={{
|
||||
mr: 3,
|
||||
width: 44,
|
||||
height: 44,
|
||||
boxShadow: 3,
|
||||
color: 'common.white',
|
||||
backgroundColor: `${item.color}.main`
|
||||
}}
|
||||
>
|
||||
{item.icon}
|
||||
</Avatar>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography variant='caption'>{item.title}</Typography>
|
||||
<Typography variant='h6'>{item.stats}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
))
|
||||
}
|
||||
|
||||
const SellerStats = () => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
title='Seller Statistics'
|
||||
subheader={
|
||||
<Typography variant='body2'>
|
||||
<Box component='span' sx={{ fontWeight: 600, color: 'text.primary' }}>
|
||||
Total 0% growth
|
||||
</Box>{' '}
|
||||
😎 this month
|
||||
</Typography>
|
||||
}
|
||||
titleTypographyProps={{
|
||||
sx: {
|
||||
mb: 2.5,
|
||||
lineHeight: '2rem !important',
|
||||
letterSpacing: '0.15px !important'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<CardContent sx={{ pt: theme => `${theme.spacing(3)} !important` }}>
|
||||
<Grid container spacing={[5, 0]}>
|
||||
{renderStats()}
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default SellerStats
|
61
components/requestDialog.tsx
Normal file
61
components/requestDialog.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import * as React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import Dialog, { DialogProps } from '@mui/material/Dialog';
|
||||
import DialogActions from '@mui/material/DialogActions';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogContentText from '@mui/material/DialogContentText';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import InputLabel from '@mui/material/InputLabel';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import Select, { SelectChangeEvent } from '@mui/material/Select';
|
||||
import Switch from '@mui/material/Switch';
|
||||
|
||||
export default function RequestDialog() {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const handleClickOpen = () => {
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Dialog
|
||||
fullWidth={fullWidth}
|
||||
maxWidth={maxWidth}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<DialogTitle>Optional sizes</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
You can set my maximum width and whether to adapt or not.
|
||||
</DialogContentText>
|
||||
<Box
|
||||
noValidate
|
||||
component="form"
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
m: 'auto',
|
||||
width: 'fit-content',
|
||||
}}
|
||||
>
|
||||
<FormControl sx={{ mt: 2, minWidth: 120 }}>
|
||||
<InputLabel htmlFor="max-width">maxWidth</InputLabel>
|
||||
</FormControl>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose}>Close</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
@ -0,0 +1,325 @@
|
||||
import * as React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Stepper from '@mui/material/Stepper';
|
||||
import Step from '@mui/material/Step';
|
||||
import StepLabel from '@mui/material/StepLabel';
|
||||
import StepContent from '@mui/material/StepContent';
|
||||
import Button from '@mui/material/Button';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Grid from '@mui/material/Grid'
|
||||
import TextField from '@mui/material/TextField';
|
||||
import ArtistDashboardRequest from '../components/OLd/artistDashboardRequest';
|
||||
import ArtistPortfolio from '../components/OLd/artistPortfolio';
|
||||
import EditableArtistPortfolio from '../components/OLd/editableArtistPortfolio';
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
|
||||
import {Card, CardContent, CardHeader, Divider } from '@mui/material';
|
||||
|
||||
|
||||
const steps = [
|
||||
{
|
||||
label: 'Request Access As Artist',
|
||||
description: `In order to start selling your art on our platform, you need to request access. Please include links to your social media and tag or DM us on the platform (@RequestDotBox). We may reach out for further verification and examples of your work.`,
|
||||
},
|
||||
{
|
||||
label: 'Onboard On Stripe',
|
||||
description:
|
||||
'Our platform uses Stripe as a payment processor. You will be required to onboard with them with all of your payout information and business information.',
|
||||
},
|
||||
{
|
||||
label: 'Setup Your Portfolio',
|
||||
description: `This is where you can setup your initial portfolio. You can upload any image format file to your portfolio. It will be automatically displayed on your artist page. You can add and remove from this later.`,
|
||||
},
|
||||
{
|
||||
label: 'Configure Your Artist Page',
|
||||
description: `Every artist gets their own public facing page that they can send to anyone or post anywhere. You have full control over the colors, logos, and more of this page.`,
|
||||
},
|
||||
];
|
||||
|
||||
export default function onboarding() {
|
||||
const [activeStep, setActiveStep] = React.useState(0);
|
||||
const [sellerRequestData, setArtistRequestData] = React.useState(null);
|
||||
const [profileData, setArtistData] = React.useState(null);
|
||||
const [isStripeOnboarded, setIsStripeOnboarded] = React.useState(false);
|
||||
const [onBoardUrl, setOnBoardUrl] = React.useState("");
|
||||
|
||||
|
||||
|
||||
const handleNext = () => {
|
||||
setActiveStep((prevActiveStep) => prevActiveStep + 1);
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
setActiveStep((prevActiveStep) => prevActiveStep - 1);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setActiveStep(0);
|
||||
};
|
||||
|
||||
const getData = async () => {
|
||||
const onboardCheckRequest = await fetch('/api/artist/onboarded', { method: "GET" });
|
||||
const onboardCheckResponse = await onboardCheckRequest.json();
|
||||
setIsStripeOnboarded(onboardCheckResponse["onboarded"]);
|
||||
const onboardUrlRequest = await fetch('/api/artist/onboardurl', { method: "GET" });
|
||||
const onboardUrlResponse = await onboardUrlRequest.json();
|
||||
setOnBoardUrl(onboardUrlResponse["onboardUrl"]);
|
||||
const response = await fetch('/api/artist/request');
|
||||
const sellerRequest = await response.json();
|
||||
setArtistRequestData(sellerRequest);
|
||||
const profileResponse = await fetch('/api/artist/profile');
|
||||
const sellerProfile = await profileResponse.json();
|
||||
setArtistData(sellerProfile);
|
||||
|
||||
setTimeout(getData, 5000); // Poll every 5 seconds (adjust as needed)
|
||||
}
|
||||
React.useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
const requestButton = () => {
|
||||
fetch('/api/artist/newRequest').then((response) => {
|
||||
if (response.ok) {
|
||||
fetch('/api/artist/request').then((requestResponse) => {
|
||||
requestResponse.json().then((sellerRequest) => {
|
||||
setArtistRequestData(sellerRequest);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let formattedTime = ""
|
||||
if (sellerRequestData) {
|
||||
const date = new Date(sellerRequestData["requestDate"]);
|
||||
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
|
||||
}
|
||||
|
||||
if(activeStep==4){
|
||||
window.location.href="/dashboard"
|
||||
}
|
||||
|
||||
return (
|
||||
<Card sx={{ width:"100%", padding:"2%" }}>
|
||||
<Stepper activeStep={activeStep} orientation="vertical">
|
||||
{steps.map((step, index) => (
|
||||
<Step key={step.label}>
|
||||
<StepLabel
|
||||
optional={
|
||||
index === 3 ? (
|
||||
<Typography variant="caption">Last step</Typography>
|
||||
) : null
|
||||
}
|
||||
>
|
||||
{step.label}
|
||||
</StepLabel>
|
||||
{(index==0) ? (
|
||||
<StepContent>
|
||||
<Grid container >
|
||||
<Grid item xs={12} lg={6}>
|
||||
<Typography>{step.description}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={6}>
|
||||
</Grid>
|
||||
{(sellerRequestData && Object.keys(sellerRequestData).length>0) ? (
|
||||
<Grid item xs={12} lg={6} sx={{paddingTop:"2%"}}>
|
||||
<ArtistDashboardRequest/>
|
||||
</Grid>
|
||||
):(
|
||||
<Grid item xs={12} lg={6}>
|
||||
<TextField fullWidth rows={4} multiline label="Application Message" variant="outlined" />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
<Box sx={{ mb: 2 ,paddingTop:"2%"}}>
|
||||
<div>
|
||||
{(sellerRequestData && Object.keys(sellerRequestData).length>0) ? (
|
||||
(sellerRequestData["accepted"]) ? (
|
||||
<Button variant="contained" onClick={handleNext}>
|
||||
Continue
|
||||
</Button>
|
||||
) : (
|
||||
|
||||
<Button variant="contained" disabled>
|
||||
Request Pending
|
||||
</Button> )
|
||||
):
|
||||
(
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={requestButton}
|
||||
sx={{ mt: 1, mr: 1 }}
|
||||
>
|
||||
Request Access
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
</StepContent>
|
||||
): null}
|
||||
{(index==1) ? (
|
||||
<StepContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} lg={6}>
|
||||
<Typography>{step.description}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Box sx={{ mb: 2 }}>
|
||||
<div>
|
||||
{isStripeOnboarded==true ? (
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleNext}
|
||||
sx={{ mt: 1, mr: 1 }}
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
):(
|
||||
|
||||
<Button
|
||||
color='success'
|
||||
variant="contained"
|
||||
href={onBoardUrl}
|
||||
sx={{ mt: 1, mr: 1 }}
|
||||
>
|
||||
ONBOARD WITH STRIPE
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
</StepContent>
|
||||
): null}
|
||||
{(index==2) ? (
|
||||
<StepContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} lg={6}>
|
||||
<Typography>{step.description}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={6}>
|
||||
<EditableArtistPortfolio artistId={profileData ? profileData["id"] : null}/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Box sx={{ mb: 2 }}>
|
||||
<div>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleNext}
|
||||
sx={{ mt: 1, mr: 1 }}
|
||||
>
|
||||
{index === steps.length - 1 ? 'Finish' : 'Continue'}
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
</StepContent>
|
||||
): null}
|
||||
{(index==3) ? (
|
||||
<StepContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} lg={6}>
|
||||
<Typography>{step.description}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={6}>
|
||||
|
||||
</Grid>
|
||||
<Grid container sx={{paddingTop:"50px"}}>
|
||||
<Grid item xs={12} lg={2}>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={8}>
|
||||
<Card elevation={5}>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} lg={12} sx={{textAlign:"center"}}>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
Artist Name
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={12} sx={{textAlign:"center", paddingTop:"2%"}}>
|
||||
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Biography
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={12} sx={{textAlign:"center"}}>
|
||||
|
||||
<Typography variant="body1" gutterBottom>
|
||||
TAwehtwaehrewaoioirewaoihroiewahroiewahriewaohroiewahroiweahroiewahrhweaoirhewaiorhewaoirhewaoirhewaoirhweah
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={12} sx={{textAlign:"center", paddingTop:"2%"}}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Portfolio
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={12} sx={{textAlign:"center"}}>
|
||||
<ArtistPortfolio artistId={profileData ? profileData["id"] : null}/>
|
||||
</Grid> <Divider/>
|
||||
<Divider/>
|
||||
<Grid item xs={12} lg={12} sx={{textAlign:"center", paddingTop:"2%"}}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Requests
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid container sx={{textAlign:"center"}}>
|
||||
<Grid item xs={12} lg={6} sx={{textAlign:"center", paddingTop:"2%"}}>
|
||||
|
||||
<TextField fullWidth disabled multiline rows={8} sx={{padding:"2%"}} label="Request Guidelines" value="These are the terms of your requests.">
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={6} sx={{textAlign:"center", paddingTop:"2%"}}>
|
||||
|
||||
<TextField fullWidth multiline rows={4} sx={{padding:"2%"}} label="Your Request Terms">
|
||||
</TextField>
|
||||
|
||||
<CurrencyTextField
|
||||
label="Offer Amount"
|
||||
variant="standard"
|
||||
value={0}
|
||||
currencySymbol="USD "
|
||||
//minimumValue="0"
|
||||
outputFormat="string"
|
||||
|
||||
decimalCharacter="."
|
||||
digitGroupSeparator=","/>
|
||||
<Button color="primary" variant="contained" sx={{paddingTop:"2%"}}>Submit</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Divider/>
|
||||
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={2}>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Box sx={{ mb: 2 }}>
|
||||
<div>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleNext}
|
||||
sx={{ mt: 1, mr: 1 }}
|
||||
>
|
||||
{index === steps.length - 1 ? 'Finish' : 'Continue'}
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
</StepContent>
|
||||
): null}
|
||||
</Step>
|
||||
))}
|
||||
</Stepper>
|
||||
{activeStep === steps.length && (
|
||||
<Paper square elevation={0} sx={{ p: 3 }}>
|
||||
<Typography>All steps completed - you're finished</Typography>
|
||||
<Button onClick={handleReset} sx={{ mt: 1, mr: 1 }}>
|
||||
Reset
|
||||
</Button>
|
||||
</Paper>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
@ -23,7 +23,7 @@ import { Settings } from '../../../core/context/settingsContext'
|
||||
import ModeToggler from '../../../core/layouts/components/shared-components/ModeToggler'
|
||||
import UserDropdown from '../../../core/layouts/components/shared-components/UserDropdown'
|
||||
import NotificationDropdown from '../../../core/layouts/components/shared-components/NotificationDropdown'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
interface Props {
|
||||
hidden: boolean
|
||||
settings: Settings
|
||||
@ -38,7 +38,18 @@ const AppBarContent = (props: Props) => {
|
||||
// ** Hook
|
||||
const hiddenSm = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm'))
|
||||
|
||||
return (
|
||||
const [profileData, setProfileData] = useState(null);
|
||||
|
||||
const getData = async () => {
|
||||
const artistProfileRequest = await fetch('/api/me', { method: "GET" });
|
||||
const artistProfileResponse = await artistProfileRequest.json();
|
||||
setProfileData(artistProfileResponse);
|
||||
}
|
||||
|
||||
//console.log(profileData)
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []); return (
|
||||
<Box sx={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Box className='actions-left' sx={{ mr: 2, display: 'flex', alignItems: 'center' }}>
|
||||
{hidden ? (
|
||||
@ -52,12 +63,13 @@ const AppBarContent = (props: Props) => {
|
||||
) : null}
|
||||
</Box>
|
||||
<Box className='actions-right' sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
|
||||
<NovuProvider subscriberId={'on-boarding-subscriber-id-123'} applicationIdentifier={'9SKjzgN_odAF'}>
|
||||
{(profileData ? (
|
||||
<NovuProvider subscriberId={profileData["id"]} applicationIdentifier={'9SKjzgN_odAF'}>
|
||||
<PopoverNotificationCenter colorScheme={'light'}>
|
||||
{({ unseenCount }) => <NotificationBell unseenCount={unseenCount} />}
|
||||
</PopoverNotificationCenter>
|
||||
</NovuProvider>
|
||||
):null)}
|
||||
<UserDropdown />
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -7,80 +7,99 @@ import SettingsApplicationsIcon from '@mui/icons-material/SettingsApplications';
|
||||
|
||||
// ** Type import
|
||||
import { VerticalNavItemsType } from '../../core/layouts/types'
|
||||
import { BankTransfer, PageFirst } from 'mdi-material-ui'
|
||||
import { BankTransfer, Cart, Clipboard, PageFirst } from 'mdi-material-ui'
|
||||
import { DocumentScanner, FileOpen, Settings } from '@mui/icons-material'
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
const navigation = (): VerticalNavItemsType => {
|
||||
const [isStripeOnboarded, setIsStripeOnboarded] = useState(false);
|
||||
const [profileData, setProfileData] = useState(null);
|
||||
const [userData, setUserData] = useState(null);
|
||||
|
||||
const getData = async () => {
|
||||
|
||||
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'
|
||||
},
|
||||
{
|
||||
title: 'Dashboard',
|
||||
icon: HomeOutline,
|
||||
path: '/dashboard'
|
||||
},
|
||||
{
|
||||
title: 'Account Settings',
|
||||
icon: Settings,
|
||||
path: '/dashboard/settings'
|
||||
},
|
||||
var result = [
|
||||
{
|
||||
sectionTitle: 'Admin'
|
||||
},
|
||||
{
|
||||
title: 'Artist Requests',
|
||||
icon: Clipboard,
|
||||
path: '/dashboard/admin/requests'
|
||||
},
|
||||
{
|
||||
sectionTitle: 'General'
|
||||
},
|
||||
{
|
||||
title: 'Dashboard',
|
||||
icon: HomeOutline,
|
||||
path: '/dashboard'
|
||||
},
|
||||
{
|
||||
title: 'Account Settings',
|
||||
icon: Settings,
|
||||
path: '/dashboard/settings'
|
||||
},
|
||||
{
|
||||
title: 'Your Requests',
|
||||
icon: Cart,
|
||||
path: '/dashboard/requests'
|
||||
}
|
||||
];
|
||||
|
||||
if (isStripeOnboarded) {
|
||||
result.push(
|
||||
{
|
||||
sectionTitle: 'Artist'
|
||||
},
|
||||
{
|
||||
title: 'Incoming Requests',
|
||||
icon: CubeOutline,
|
||||
path: '/dashboard/artist/requests'
|
||||
},
|
||||
{
|
||||
title: 'Payments/Payouts',
|
||||
icon: BankTransfer,
|
||||
path: '/dashboard/payout'
|
||||
},
|
||||
{
|
||||
title: 'Shop Settings',
|
||||
icon: SettingsApplicationsIcon,
|
||||
path: '/dashboard/artist/artistsettings'
|
||||
},
|
||||
{
|
||||
title: 'Payout Portal',
|
||||
icon: BankTransfer,
|
||||
path: '/payoutportal'
|
||||
},
|
||||
{
|
||||
title: 'Page Settings',
|
||||
icon: DocumentScanner,
|
||||
path: '/dashboard/artist/pagesettings'
|
||||
},
|
||||
{
|
||||
title: 'Preview Page',
|
||||
title: 'Your Page',
|
||||
icon: FileOpen,
|
||||
path: '/artist/pagesettings'
|
||||
path: '/box/' + (userData ? userData["displayName"] : "")
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
else{
|
||||
|
||||
return [
|
||||
{
|
||||
sectionTitle: 'General'
|
||||
},
|
||||
{
|
||||
title: 'Dashboard',
|
||||
icon: HomeOutline,
|
||||
path: '/dashboard'
|
||||
},
|
||||
{
|
||||
title: 'Account Settings',
|
||||
icon: Settings,
|
||||
path: '/dashboard/settings'
|
||||
},
|
||||
]
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export default navigation
|
||||
export default navigation;
|
||||
|
||||
|
9
package-lock.json
generated
9
package-lock.json
generated
@ -20,6 +20,7 @@
|
||||
"apexcharts": "^3.45.2",
|
||||
"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",
|
||||
@ -1931,6 +1932,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",
|
||||
|
@ -21,6 +21,7 @@
|
||||
"apexcharts": "^3.45.2",
|
||||
"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",
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useUser } from "@auth0/nextjs-auth0/client";
|
||||
import Layout from "../../components/OLd/layout";
|
||||
import Layout from "../../components/Old/layout";
|
||||
|
||||
const ApiProfile = () => {
|
||||
const { user, isLoading } = useUser();
|
||||
|
17
pages/api/admin/requests.tsx
Normal file
17
pages/api/admin/requests.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
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/admin/AdminArtistRequests', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/admin/requests/[userId].tsx
Normal file
19
pages/api/admin/requests/[userId].tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { userId } = req.query;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtistRequests/'+userId, {
|
||||
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);
|
||||
});
|
||||
|
@ -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);
|
||||
|
@ -2,12 +2,15 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a
|
||||
|
||||
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/SellerProfile/Onboard', {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Onboard', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
@ -2,7 +2,7 @@ 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}`
|
||||
}
|
||||
|
29
pages/api/artist/page.tsx
Normal file
29
pages/api/artist/page.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function pageSettings(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
if(req.method !== 'GET') {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Page', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
method: "PUT",
|
||||
body: JSON.stringify(req.body)
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
||||
else{
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Page', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
|
||||
//console.log(response)
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
||||
});
|
||||
|
21
pages/api/artist/payout.tsx
Normal file
21
pages/api/artist/payout.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function products(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
////console.log(accessToken)
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Payout', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
method: 'GET'
|
||||
});
|
||||
if(response.status == 404)
|
||||
{
|
||||
res.status(200).json({})
|
||||
}
|
||||
else{
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
||||
});
|
||||
|
@ -26,7 +26,7 @@ export default withApiAuthRequired(async function handler(req, res) {
|
||||
const file = files["newImage"]; // Assuming your file input field name is 'file'
|
||||
try {
|
||||
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL + '/api/SellerProfile/Portfolio', {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL + '/api/Artist/Portfolio', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
|
@ -16,7 +16,7 @@ export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { id } = req.query;
|
||||
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL + '/api/SellerProfile/Portfolio/'+id, {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL + '/api/Artist/Portfolio/'+id, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
|
@ -3,7 +3,7 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a
|
||||
export default withApiAuthRequired(async function sellerProfile(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
if(req.method !== 'GET') {
|
||||
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}`,
|
||||
"Content-Type": "application/json"
|
||||
@ -16,7 +16,7 @@ export default withApiAuthRequired(async function sellerProfile(req, res) {
|
||||
res.status(200).json(result);
|
||||
}
|
||||
else{
|
||||
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}`
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a
|
||||
|
||||
export default withApiAuthRequired(async function products(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/SellerProfile/Request', {
|
||||
////console.log(accessToken)
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Request', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
|
19
pages/api/artist/requestcount.tsx
Normal file
19
pages/api/artist/requestcount.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
|
||||
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Artist/Count?completed=${completed}&declined=${declined}&accepted=${accepted}&paid=${paid}&offset=${offset}&pageSize=${pageSize}`;
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/artist/requests.tsx
Normal file
19
pages/api/artist/requests.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
|
||||
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Artist?completed=${completed}&declined=${declined}&accepted=${accepted}&paid=${paid}&offset=${offset}&pageSize=${pageSize}`;
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
16
pages/api/artist/requests/[requestId]/accept.tsx
Normal file
16
pages/api/artist/requests/[requestId]/accept.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function 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+'/Accept', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'PUT'
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
17
pages/api/artist/requests/[requestId]/complete.tsx
Normal file
17
pages/api/artist/requests/[requestId]/complete.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function 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+'/Complete', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'PUT'
|
||||
});
|
||||
console.log(response)
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
16
pages/api/artist/requests/[requestId]/deny.tsx
Normal file
16
pages/api/artist/requests/[requestId]/deny.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function 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+'/Deny', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'PUT'
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
21
pages/api/artist/stats.tsx
Normal file
21
pages/api/artist/stats.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function products(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
////console.log(accessToken)
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist/Stats', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
},
|
||||
method: 'GET'
|
||||
});
|
||||
if(response.status == 404)
|
||||
{
|
||||
res.status(200).json({})
|
||||
}
|
||||
else{
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
||||
});
|
||||
|
@ -1,3 +1,6 @@
|
||||
import { handleAuth } from "@auth0/nextjs-auth0";
|
||||
|
||||
exports.onExecutePostLogin = async (event, api) => {
|
||||
const namespace = 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role';
|
||||
//console.log(event.authorization)
|
||||
}
|
||||
export default handleAuth();
|
||||
|
14
pages/api/box/[artistName].tsx
Normal file
14
pages/api/box/[artistName].tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
|
||||
export default async function handler(req, res ): Promise<any> {
|
||||
const { artistName } = req.query;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${artistName}/Page`;
|
||||
const response = await fetch(url);
|
||||
//console.log(response)
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch seller');
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
24
pages/api/box/newRequest.tsx
Normal file
24
pages/api/box/newRequest.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { getAccessToken } from '@auth0/nextjs-auth0';
|
||||
|
||||
|
||||
export default async function handler(req, res ): Promise<any> {
|
||||
const { artistName } = req.query;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Requests/Request`;
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(url,{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: req.body
|
||||
});
|
||||
//console.log(response)
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch seller');
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
@ -3,7 +3,7 @@ import { useRouter } from 'next/router'
|
||||
|
||||
export default async function handler(req, res ): Promise<any> {
|
||||
const { sellerId } = req.query;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${sellerId}`;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch seller');
|
||||
|
@ -1,6 +1,6 @@
|
||||
export default async function handler(req, res ): Promise<any> {
|
||||
const { sellerId } = req.query;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${sellerId}/Portfolio`;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}/Portfolio`;
|
||||
(url)
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
|
@ -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');
|
||||
|
@ -5,7 +5,7 @@ import { getAccessToken } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function me(req, res) {
|
||||
if(req.method !== 'GET') {
|
||||
console.log(req.body)
|
||||
////console.log(req.body)
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/User', {
|
||||
headers: {
|
||||
|
19
pages/api/requestcount.tsx
Normal file
19
pages/api/requestcount.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function 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/Customer/Count?completed=${completed}&declined=${declined}&accepted=${accepted}&paid=${paid}&offset=${offset}&pageSize=${pageSize}`;
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
if(response.ok==false){
|
||||
res.status(200).json({})
|
||||
return;
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
19
pages/api/requests.tsx
Normal file
19
pages/api/requests.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function 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/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);
|
||||
});
|
||||
|
15
pages/api/requests/[requestId]/payment.tsx
Normal file
15
pages/api/requests/[requestId]/payment.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function 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/Customer/'+requestId+'/Payment', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
17
pages/api/requests/[requestId]/references.tsx
Normal file
17
pages/api/requests/[requestId]/references.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
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/Customer/'+requestId+'/Reference', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: req.method,
|
||||
body: req.body
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
317
pages/box/[artistName].tsx
Normal file
317
pages/box/[artistName].tsx
Normal file
@ -0,0 +1,317 @@
|
||||
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/Old/artistPortfolio";
|
||||
import { RouterNetwork } from "mdi-material-ui";
|
||||
import { useRouter } from "next/router";
|
||||
import { profile } from "console";
|
||||
import FileOpen from "@mui/icons-material/FileOpen";
|
||||
|
||||
const Profile = () => {
|
||||
|
||||
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) => {
|
||||
const formData = new FormData();
|
||||
formData.append("artistId", payload.artistId);
|
||||
formData.append("message", payload.message);
|
||||
formData.append("amount", payload.amount);
|
||||
formData.append("file", payload.file); // Append the file to FormData
|
||||
|
||||
const requestResponse = await fetch('/api/box/newRequest', {
|
||||
method: 'POST',
|
||||
body: formData // Pass FormData containing the file
|
||||
});
|
||||
|
||||
if(requestResponse.ok){
|
||||
router.push("/dashboard/requests")
|
||||
} else {
|
||||
alert("Error submitting request")
|
||||
}
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
const columns: GridColDef[] = [
|
||||
{
|
||||
field: 'message',
|
||||
headerName: 'Review',
|
||||
flex: 0.75
|
||||
},
|
||||
{
|
||||
field: 'rating',
|
||||
headerName: 'Rating',
|
||||
flex: 0.25,
|
||||
renderCell: (params: GridValueGetterParams) => (
|
||||
<Rating name="read-only" value={params.value} readOnly />
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const rows = [
|
||||
{ id: 1, message: 'Great work!', rating: 5 },
|
||||
{ id: 2, message: 'BAD work!', rating: 1 },
|
||||
{ id: 3, message: 'Okay work!', rating: 4 },
|
||||
{ id: 4, message: 'Meh work!', rating: 2 },
|
||||
{ id: 5, message: 'Great work!', rating: 5 },
|
||||
{ id: 6, message: 'Mid work!', rating: 3 },
|
||||
{ id: 7, message: 'HORRIBLE work!', rating: 1 },
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
PaperProps={{
|
||||
component: 'form',
|
||||
onSubmit: (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
const formData = new FormData(event.currentTarget);
|
||||
const email = formData.get("email");
|
||||
const file = formData.get("file"); // Get the file object
|
||||
const payload = {
|
||||
artistId: profileData["id"],
|
||||
message: requestMessage,
|
||||
amount: requestPrice,
|
||||
file: file // Include the file in the payload
|
||||
};
|
||||
submitRequest(payload);
|
||||
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="name"
|
||||
name="message"
|
||||
label="Request Message"
|
||||
type="message"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
multiline
|
||||
rows={10}
|
||||
onChange={handleRequestMessageChange}
|
||||
value={requestMessage}
|
||||
/>
|
||||
<CurrencyTextField
|
||||
label="Price"
|
||||
variant="standard"
|
||||
currencySymbol="$"
|
||||
outputFormat="number"
|
||||
decimalCharacter="."
|
||||
digitGroupSeparator=","
|
||||
fullWidth
|
||||
onChange={handleRequestPriceChange}
|
||||
value={requestPrice}
|
||||
/>
|
||||
|
||||
<input
|
||||
id="file"
|
||||
name="file"
|
||||
style={{ display: 'none' }}
|
||||
accept="image/*"
|
||||
type="file"
|
||||
multiple
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
<label htmlFor="file">
|
||||
<Button
|
||||
fullWidth
|
||||
|
||||
variant='outlined'
|
||||
component="span"
|
||||
size="large"
|
||||
sx={{width:"100%"}}
|
||||
startIcon={<FileOpen />}
|
||||
>
|
||||
Select Your Reference Images
|
||||
</Button>
|
||||
</label>
|
||||
</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} >
|
||||
<DataGrid
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
autoHeight={true}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: {
|
||||
pageSize: 5,
|
||||
},
|
||||
},
|
||||
}}
|
||||
pageSizeOptions={[5]}
|
||||
/>
|
||||
</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(Profile);
|
||||
|
||||
|
50
pages/dashboard/admin/requests.tsx
Normal file
50
pages/dashboard/admin/requests.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
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 EditableArtistPortfolio from "../../../components/Old/editableArtistPortfolio";
|
||||
import { useEffect, useState } from "react";
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Button from '@mui/material/Button';
|
||||
import Switch from '@mui/material/Switch';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import ArtistRequest from "../../../components/ArtistRequest";
|
||||
|
||||
const ArtistRequests = () => {
|
||||
const {user, isLoading} = useUser();
|
||||
const [artistRequestData, setArtistRequestData] = useState(null);
|
||||
const getData = () => {
|
||||
fetch('/api/admin/requests').then(response => response.json().then(data => setArtistRequestData(data)))
|
||||
}
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, []);
|
||||
return (
|
||||
<Grid container spacing={2}>
|
||||
{(artistRequestData != null && Object.keys(artistRequestData).length>0) ? (
|
||||
(artistRequestData.map((request) => {
|
||||
|
||||
let formattedTime = "";
|
||||
if (artistRequestData) {
|
||||
const date = new Date(request["requestDate"]);
|
||||
formattedTime = date.toLocaleTimeString('en-US', {
|
||||
month: 'long',
|
||||
day: '2-digit',
|
||||
year: 'numeric',
|
||||
hour12: true,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
}); // Example format
|
||||
}
|
||||
return (
|
||||
<ArtistRequest userid={request["userId"]} id={request["id"]} username={""} message={request["message"]} date={formattedTime} reload={getData} />
|
||||
)
|
||||
}
|
||||
))
|
||||
):(<Typography>No requests</Typography>)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
// Protected route, checking user authentication client-side.(CSR)
|
||||
export default withPageAuthRequired(ArtistRequests);
|
@ -1,5 +1,5 @@
|
||||
import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
||||
import { Grid, Typography } from "@mui/material";
|
||||
import { CircularProgress, Grid, Typography } from "@mui/material";
|
||||
import Card from "@mui/material/Card";
|
||||
import CardContent from "@mui/material/CardContent";
|
||||
import EditableArtistPortfolio from "../../../components/Old/editableArtistPortfolio";
|
||||
@ -8,9 +8,12 @@ import TextField from '@mui/material/TextField';
|
||||
import Button from '@mui/material/Button';
|
||||
import Switch from '@mui/material/Switch';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import ArtistRequest from "../../../components/ArtistRequest";
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
const ArtistSettings = () => {
|
||||
const {user, isLoading} = useUser();
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const [name, setName] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
@ -21,7 +24,7 @@ const ArtistSettings = () => {
|
||||
const [guidelines, setGuidelines] = useState("");
|
||||
const [saved, setSaved] = useState(false);
|
||||
|
||||
const [profileData, setSellerProfileData] = useState(null);
|
||||
const [profileData, setArtistData] = useState(null);
|
||||
|
||||
const handleDisplayNameChange = (event) => {
|
||||
setName(event.target.value);
|
||||
@ -64,13 +67,22 @@ const saveChanges = async () => {
|
||||
setSocial3(sellerProfile["socialMeidaLink3"]);
|
||||
setSocial4(sellerProfile["socialMeidaLink4"]);
|
||||
setGuidelines(sellerProfile["requestGuidelines"]);
|
||||
setSellerProfileData(sellerProfile);
|
||||
setArtistData(sellerProfile);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
{(loading) ? (
|
||||
<Box sx={{textAlign:"center", paddingTop:"20%"}}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
):
|
||||
(
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card>
|
||||
@ -83,7 +95,7 @@ const saveChanges = async () => {
|
||||
<Button variant="contained" onClick={saveChanges} color="success" fullWidth>{saved ? "Saved" : "Save Changes"}</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Grid container spacing={2} sx={{paddingTop:"2%"}}>
|
||||
<Grid container spacing={4} sx={{paddingTop:"2%"}}>
|
||||
<Grid item xs={12} md={12} sx={{paddingTop:"2%"}}>
|
||||
<TextField id="outlined-basic" label="Shop Name" value={name} onChange={handleDisplayNameChange} size="small" variant="outlined" fullWidth />
|
||||
</Grid>
|
||||
@ -93,7 +105,7 @@ const saveChanges = async () => {
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Grid container spacing={2} sx={{paddingTop:"2%"}}>
|
||||
<Grid container spacing={4} sx={{paddingTop:"2%"}}>
|
||||
<Grid item xs={12} md={6} sx={{paddingTop:"2%"}}>
|
||||
<TextField id="outlined-basic" label="Social Media 1" value={social1} onChange={handleSocial1Change} type="url" size="small" variant="outlined" fullWidth />
|
||||
</Grid>
|
||||
@ -124,6 +136,8 @@ const saveChanges = async () => {
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,602 +1,185 @@
|
||||
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 { Accordion, Typography } from "@mui/material";
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { useEffect, useState } from "react";
|
||||
import Switch from '@mui/material/Switch';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import { MuiColorInput } from 'mui-color-input'
|
||||
import { AccordionSummary } from "@mui/material";
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import AccordionDetails from '@mui/material/AccordionDetails';
|
||||
import Slider from '@mui/material/Slider';
|
||||
import ArtistPortfolio from '../../../components/Old/artistPortfolio';
|
||||
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
|
||||
import EditableArtistPortfolio from "../../../components/Old/editableArtistPortfolio";
|
||||
import ArtistPortfolio from "../../../components/Old/artistPortfolio";
|
||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid';
|
||||
import Rating from '@mui/material/Rating';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
const Profile = () => {
|
||||
|
||||
const [profileData, setSellerProfileData] = useState(null);
|
||||
const [profileData, setArtistData] = useState(null);
|
||||
const [description, setDescription] = useState("");
|
||||
const [guidelines, setGuidelines] = useState("");
|
||||
|
||||
const [backgroundColor, setBackgroundColor] = useState('rgb(126, 115, 115)');
|
||||
|
||||
const [headerColor, setHeaderColor] = useState('rgb(194, 187, 187)');
|
||||
const [headerIsImage, setHeaderImage] = useState(false);
|
||||
const [headerImageUrl, setHeaderImageUrl] = useState('');
|
||||
const [headerText, setHeaderText] = useState('Shop');
|
||||
const [headerSize, setHeaderSize] = useState(5);
|
||||
const headerVariant = [
|
||||
'h6', // Size 1
|
||||
'h5', // Size 2
|
||||
'h4', // Size 3
|
||||
'h3', // Size 4
|
||||
'h2', // Size 5
|
||||
'h1', // Size 6
|
||||
][headerSize - 1] || 'h6';
|
||||
|
||||
|
||||
const [bioColor, setBioColor] = useState('rgb(186, 186, 186)');
|
||||
const [bioBgColor, setBioBgColor] = useState('rgb(78, 73, 73)');
|
||||
const [bioHeaderColor, setBioHeaderColor] = useState('rgb(194, 187, 187)');
|
||||
const [bioHeaderIsImage, setBioHeaderImage] = useState(false);
|
||||
const [bioHeaderImageUrl, setBioHeaderImageUrl] = useState('');
|
||||
const [bioHeaderText, setBioHeaderText] = useState('Biography');
|
||||
const [bioHeaderSize, setBioHeaderSize] = useState(3);
|
||||
const [bioSize, setBioSize] = useState(1);
|
||||
const bioHeaderVariant = [
|
||||
'h6', // Size 1
|
||||
'h5', // Size 2
|
||||
'h4', // Size 3
|
||||
'h3', // Size 4
|
||||
'h2', // Size 5
|
||||
'h1', // Size 6
|
||||
][bioHeaderSize - 1] || 'h6';
|
||||
const bioVariant = [
|
||||
'h6', // Size 1
|
||||
'h5', // Size 2
|
||||
'h4', // Size 3
|
||||
'h3', // Size 4
|
||||
'h2', // Size 5
|
||||
'h1', // Size 6
|
||||
][bioSize - 1] || 'h6';
|
||||
|
||||
const [portfolioHeaderColor, setPortfolioHeaderColor] = useState('rgb(194, 187, 187)');
|
||||
const [portfolioHeaderIsImage, setPortfolioHeaderImage] = useState(false);
|
||||
const [portfolioHeaderImageUrl, setPortfolioHeaderImageUrl] = useState('');
|
||||
const [portfolioHeaderText, setPortfolioHeaderText] = useState('Portfolio');
|
||||
const [portfolioHeaderSize, setPortfolioHeaderSize] = useState(3);
|
||||
const [portfolioBgColor, setPortfolioBgColor] = useState('rgb(78, 73, 73)');
|
||||
const [portfolioColumns, setPotrfolioColumns] = useState(2);
|
||||
const [portfolioWoven, setPortfolioWoven] = useState(true);
|
||||
const [portfolioShouldScroll, setPortfolioShouldScroll] = useState(true);
|
||||
const [portfolioSize, setPortfolioSize] = useState(25);
|
||||
const portfolioVariant = [
|
||||
'h6', // Size 1
|
||||
'h5', // Size 2
|
||||
'h4', // Size 3
|
||||
'h3', // Size 4
|
||||
'h2', // Size 5
|
||||
'h1', // Size 6
|
||||
][portfolioHeaderSize - 1] || 'h6';
|
||||
|
||||
|
||||
|
||||
|
||||
const [requestHeaderColor, setRequestHeaderColor] = useState('rgb(194, 187, 187)');
|
||||
const [requestHeaderIsImage, setRequestHeaderImage] = useState(false);
|
||||
const [requestHeaderImageUrl, setRequestHeaderImageUrl] = useState('');
|
||||
const [requestHeaderText, setRequestHeaderText] = useState('Requests');
|
||||
const [requestHeaderSize, setRequestHeaderSize] = useState(3);
|
||||
const [requestBgColor, setRequestBgColor] = useState('rgb(78, 73, 73)');
|
||||
const [requestTermsTextColor, setRequestTermsTextColor] = useState('rgb(194, 187, 187)');
|
||||
const [requestButtonBGColor, setRequestButtonBGColor] = useState('rgb(101, 97, 97)');
|
||||
const [requestButtonTextColor, setRequestButtonTextColor] = useState('rgb(194, 187, 187)');
|
||||
const [requestHoverButtonBGColor, setRequestHoverButtonBGColor] = useState('rgb(98, 98, 98)');
|
||||
const [requestHoverButtonTextColor, setRequestHoverButtonTextColor] = useState('rgb(194, 187, 187)');
|
||||
const requestVariant = [
|
||||
'h6', // Size 1
|
||||
'h5', // Size 2
|
||||
'h4', // Size 3
|
||||
'h3', // Size 4
|
||||
'h2', // Size 5
|
||||
'h1', // Size 6
|
||||
][requestHeaderSize - 1] || 'h6';
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const getData = async () => {
|
||||
const profileResponse = await fetch('/api/artist/profile');
|
||||
const sellerProfile = await profileResponse.json();
|
||||
setSellerProfileData(sellerProfile);
|
||||
const profileResponse = await fetch('/api/artist/profile');
|
||||
const sellerProfile = await profileResponse.json();
|
||||
setArtistData(sellerProfile);
|
||||
|
||||
setDescription(sellerProfile["description"]);
|
||||
setGuidelines(sellerProfile["requestGuidelines"]);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, []);
|
||||
|
||||
const handleBackgroundColorChange = (newValue) => {
|
||||
setBackgroundColor(newValue)
|
||||
}
|
||||
|
||||
const handleHeaderTextChange = (e) => {
|
||||
setHeaderText(e.target.value)
|
||||
}
|
||||
|
||||
const handleHeaderImageUrl = (e) => {
|
||||
setHeaderImageUrl(e.target.value)
|
||||
}
|
||||
const handleHeaderImageToggle = (e) => {
|
||||
setHeaderImage(e.target.checked)
|
||||
};
|
||||
|
||||
const handleHeaderSize = (e, newValue) => {
|
||||
setHeaderSize(newValue)
|
||||
}
|
||||
|
||||
const handleHeaderColorChange = (newValue) => {
|
||||
setHeaderColor(newValue)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const handleBioHeaderTextChange = (e) => {
|
||||
setBioHeaderText(e.target.value)
|
||||
}
|
||||
|
||||
const handleBioHeaderImageUrl = (e) => {
|
||||
setBioHeaderImageUrl(e.target.value)
|
||||
}
|
||||
const handleBioHeaderImageToggle = (e) => {
|
||||
setBioHeaderImage(e.target.checked)
|
||||
};
|
||||
|
||||
const handleBioHeaderSize = (e, newValue) => {
|
||||
setBioHeaderSize(newValue)
|
||||
}
|
||||
const handleBioSize = (e, newValue) => {
|
||||
setBioSize(newValue)
|
||||
}
|
||||
|
||||
const handleBioHeaderColorChange = (newValue) => {
|
||||
setBioHeaderColor(newValue)
|
||||
}
|
||||
const handleBioColorChange = (newValue) => {
|
||||
setBioColor(newValue)
|
||||
}
|
||||
|
||||
const handleBioBgColorChange = (newValue) => {
|
||||
setBioBgColor(newValue)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const handlePortfolioBgColor = (newValue) => {
|
||||
setPortfolioBgColor(newValue)
|
||||
}
|
||||
|
||||
const handlePortfolioColumns = (e, newValue) => {
|
||||
setPotrfolioColumns(newValue)
|
||||
}
|
||||
const handlePortfolioWoven = (e) => {
|
||||
setPortfolioWoven(e.target.checked)
|
||||
};
|
||||
const handlePortfolioShouldScroll = (e) => {
|
||||
setPortfolioShouldScroll(e.target.checked)
|
||||
console.log(portfolioShouldScroll)
|
||||
};
|
||||
const handlePortfolioSize = (e, newValue) => {
|
||||
setPortfolioSize(newValue)
|
||||
}
|
||||
|
||||
const handlePortfolioHeaderTextChange = (e) => {
|
||||
setPortfolioHeaderText(e.target.value)
|
||||
}
|
||||
|
||||
const handlePortfolioHeaderImageUrl = (e) => {
|
||||
setPortfolioHeaderImageUrl(e.target.value)
|
||||
}
|
||||
const handlePortfolioHeaderImageToggle = (e) => {
|
||||
setPortfolioHeaderImage(e.target.checked)
|
||||
};
|
||||
|
||||
const handlePortfolioHeaderSize = (e, newValue) => {
|
||||
setPortfolioHeaderSize(newValue)
|
||||
}
|
||||
const handlePortfolioHeaderColorChange = (newValue) => {
|
||||
setPortfolioHeaderColor(newValue)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const handleRequestBgColor = (newValue) => {
|
||||
setRequestBgColor(newValue)
|
||||
}
|
||||
|
||||
const handleRequestHeaderTextChange = (e) => {
|
||||
setRequestHeaderText(e.target.value)
|
||||
}
|
||||
|
||||
const handleRequestHeaderImageUrl = (e) => {
|
||||
setRequestHeaderImageUrl(e.target.value)
|
||||
}
|
||||
const handleRequestHeaderImageToggle = (e) => {
|
||||
setRequestHeaderImage(e.target.checked)
|
||||
};
|
||||
|
||||
const handleRequestHeaderSize = (e, newValue) => {
|
||||
setRequestHeaderSize(newValue)
|
||||
}
|
||||
const handleRequestHeaderColorChange = (newValue) => {
|
||||
setRequestHeaderColor(newValue)
|
||||
}
|
||||
const handleRequestTermsTextColorChange = (newValue) => {
|
||||
setRequestTermsTextColor(newValue)
|
||||
}
|
||||
const handleRequestButtonBGColorChange = (newValue) => {
|
||||
setRequestButtonBGColor(newValue)
|
||||
}
|
||||
const handleRequestButtonTextColorChange = (newValue) => {
|
||||
setRequestButtonTextColor(newValue)
|
||||
}
|
||||
const handleRequestHoverButtonBGColorChange = (newValue) => {
|
||||
setRequestHoverButtonBGColor(newValue)
|
||||
}
|
||||
const handleRequestHoverButtonTextColorChange = (newValue) => {
|
||||
setRequestHoverButtonTextColor(newValue)
|
||||
}
|
||||
|
||||
const columns: GridColDef[] = [
|
||||
{
|
||||
field: 'message',
|
||||
headerName: 'Review',
|
||||
flex: 0.75
|
||||
},
|
||||
{
|
||||
field: 'rating',
|
||||
headerName: 'Rating',
|
||||
flex: 0.25,
|
||||
renderCell: (params: GridValueGetterParams) => (
|
||||
<Rating name="read-only" value={params.value} readOnly />
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const rows = [
|
||||
{ id: 1, message: 'Great work!', rating: 5 },
|
||||
{ id: 2, message: 'BAD work!', rating: 1 },
|
||||
{ id: 3, message: 'Okay work!', rating: 4 },
|
||||
{ id: 4, message: 'Meh work!', rating: 2 },
|
||||
{ id: 5, message: 'Great work!', rating: 5 },
|
||||
{ id: 6, message: 'Mid work!', rating: 3 },
|
||||
{ id: 7, message: 'HORRIBLE work!', rating: 1 },
|
||||
];
|
||||
|
||||
|
||||
return (
|
||||
(loading) ? (
|
||||
<Box sx={{textAlign:"center", paddingTop:"20%"}}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
):(
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={4}>
|
||||
<Card >
|
||||
<CardContent>
|
||||
<Grid container spacing={1}>
|
||||
<Grid item xs={12} md={9}>
|
||||
<Typography variant="h6" >
|
||||
Customize Your Page
|
||||
</Typography>
|
||||
<Grid 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={3}>
|
||||
<Button color="success" variant="contained" size="large">
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Divider/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Accordion defaultExpanded>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
aria-controls="panel1-content"
|
||||
>
|
||||
<Typography>Background</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput fullWidth value={backgroundColor} onChange={handleBackgroundColorChange} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Accordion defaultExpanded>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
aria-controls="panel1-content"
|
||||
>
|
||||
<Typography>Header</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<TextField disabled={headerIsImage} variant="outlined" fullWidth label="Header Text" onChange={handleHeaderTextChange} value={headerText} size="small"></TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={10}>
|
||||
<TextField variant="outlined" fullWidth label="Image Url" size="small" onChange={handleHeaderImageUrl}></TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2}>
|
||||
<Switch checked={headerIsImage} onChange={handleHeaderImageToggle} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput disabled={headerIsImage} label="Color" fullWidth value={headerColor} onChange={handleHeaderColorChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={3}>
|
||||
<Typography variant="body1" >
|
||||
Text Size
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={9}>
|
||||
<Slider disabled={headerIsImage} value={headerSize} onChange={handleHeaderSize} aria-label="Size" defaultValue={6} step={1} marks min={1} max={6} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Accordion defaultExpanded>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
aria-controls="panel1-content"
|
||||
>
|
||||
<Typography>Biography</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Grid container spacing={2}>
|
||||
|
||||
<Grid item xs={12} md={12}>
|
||||
<TextField disabled={bioHeaderIsImage} variant="outlined" fullWidth label="Header Text" onChange={handleBioHeaderTextChange} value={bioHeaderText} size="small"></TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={10}>
|
||||
<TextField variant="outlined" fullWidth label="Header Image Url" size="small" value={bioHeaderImageUrl} onChange={handleBioHeaderImageUrl}></TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2}>
|
||||
<Switch checked={bioHeaderIsImage} onChange={handleBioHeaderImageToggle} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput disabled={bioHeaderIsImage} label="Header Text Color" fullWidth value={bioHeaderColor} onChange={handleBioHeaderColorChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput label="Background Color" fullWidth value={bioBgColor} onChange={handleBioBgColorChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput label="Text Color" fullWidth value={bioColor} onChange={handleBioColorChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={5}>
|
||||
<Typography variant="body1" >
|
||||
Header Size
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={7}>
|
||||
<Slider disabled={bioHeaderIsImage} value={bioHeaderSize} onChange={handleBioHeaderSize} aria-label="Size" defaultValue={6} step={1} marks min={1} max={6} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={5}>
|
||||
<Typography variant="body1" >
|
||||
Text Size
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={7}>
|
||||
<Slider value={bioSize} onChange={handleBioSize} aria-label="Size" defaultValue={6} step={1} marks min={1} max={6} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Accordion defaultExpanded>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
aria-controls="panel1-content"
|
||||
>
|
||||
<Typography>Portfolio</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<TextField disabled={portfolioHeaderIsImage} variant="outlined" fullWidth label="Header Text" onChange={handlePortfolioHeaderTextChange} value={portfolioHeaderText} size="small"></TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={10}>
|
||||
<TextField variant="outlined" fullWidth label="Header Image Url" size="small" value={portfolioHeaderImageUrl} onChange={handlePortfolioHeaderImageUrl}></TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2}>
|
||||
<Switch checked={portfolioHeaderIsImage} onChange={handlePortfolioHeaderImageToggle} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput disabled={portfolioHeaderIsImage} label="Header Text Color" fullWidth value={portfolioHeaderColor} onChange={handlePortfolioHeaderColorChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={5}>
|
||||
<Typography variant="body1" >
|
||||
Header Size
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={7}>
|
||||
<Slider disabled={portfolioHeaderIsImage} value={portfolioHeaderSize} onChange={handlePortfolioHeaderSize} aria-label="Size" defaultValue={6} step={1} marks min={1} max={6} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput label="Background Color" fullWidth value={portfolioBgColor} onChange={handlePortfolioBgColor} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={10}>
|
||||
<Typography variant="body1" >
|
||||
Masonry Layout Enabled
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2 }>
|
||||
<Switch checked={portfolioWoven} onChange={handlePortfolioWoven} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={5}>
|
||||
<Typography variant="body1" >
|
||||
Columns
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={7}>
|
||||
<Slider value={portfolioColumns} onChange={handlePortfolioColumns} aria-label="Size" defaultValue={6} step={1} marks min={1} max={5} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={10}>
|
||||
<Typography variant="body1" >
|
||||
Enable Scrolling
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2 }>
|
||||
<Switch checked={portfolioShouldScroll} onChange={handlePortfolioShouldScroll} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<Typography variant="body1" >
|
||||
Max Size
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={8}>
|
||||
<Slider disabled={!portfolioShouldScroll} value={portfolioSize} onChange={handlePortfolioSize} aria-label="Size" defaultValue={5} step={5} marks min={1} max={100} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={12}>
|
||||
<Accordion defaultExpanded>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
aria-controls="panel1-content"
|
||||
>
|
||||
<Typography>Requests</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<TextField disabled={requestHeaderIsImage} variant="outlined" fullWidth label="Header Text" onChange={handleRequestHeaderTextChange} value={requestHeaderText} size="small"></TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={10}>
|
||||
<TextField variant="outlined" fullWidth label="Header Image Url" size="small" value={requestHeaderImageUrl} onChange={handleRequestHeaderImageUrl}></TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2}>
|
||||
<Switch checked={requestHeaderIsImage} onChange={handleRequestHeaderImageToggle} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput disabled={requestHeaderIsImage} label="Header Text Color" fullWidth value={requestHeaderColor} onChange={handleRequestHeaderColorChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={5}>
|
||||
<Typography variant="body1" >
|
||||
Header Size
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={7}>
|
||||
<Slider disabled={requestHeaderIsImage} value={requestHeaderSize} onChange={handleRequestHeaderSize} aria-label="Size" defaultValue={6} step={1} marks min={1} max={6} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput label="Background Color" fullWidth value={requestBgColor} onChange={handleRequestBgColor} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput label="Terms Text Color" fullWidth value={requestTermsTextColor} onChange={handleRequestTermsTextColorChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput label="Button BG Color" fullWidth value={requestButtonBGColor} onChange={handleRequestButtonBGColorChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput label="Button Text Color" fullWidth value={requestButtonTextColor} onChange={handleRequestButtonTextColorChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput label="Button Hover BG Color" fullWidth value={requestHoverButtonBGColor} onChange={handleRequestHoverButtonBGColorChange} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<MuiColorInput label="Button Hover Text Color" fullWidth value={requestHoverButtonTextColor} onChange={handleRequestHoverButtonTextColorChange} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={8}>
|
||||
<Grid container spacing={1}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Card sx={{backgroundColor:backgroundColor}}>
|
||||
<CardContent>
|
||||
<Grid container spacing={1}>
|
||||
<Grid item xs={12} md={12} sx={{textAlign:"center"}}>
|
||||
{(headerIsImage) ? (
|
||||
<img src={headerImageUrl} alt="Header Image" />
|
||||
) : (
|
||||
<Typography variant={headerVariant} color={headerColor}>
|
||||
{headerText}
|
||||
</Typography>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} sx={{textAlign:"center", marginTop:"2%"}}>
|
||||
<Card sx={{backgroundColor:bioBgColor}}>
|
||||
<CardContent>
|
||||
{(bioHeaderIsImage) ? (
|
||||
<img src={bioHeaderImageUrl} alt="Header Image" />
|
||||
) : (
|
||||
<Typography variant={bioHeaderVariant} color={bioHeaderColor}>
|
||||
{bioHeaderText}
|
||||
</Typography>
|
||||
)}
|
||||
<Typography variant={bioVariant} color={bioColor} > {(profileData ? profileData["biography"]:null)}
|
||||
<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>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</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 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} >
|
||||
<DataGrid
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
autoHeight={true}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: {
|
||||
pageSize: 5,
|
||||
},
|
||||
},
|
||||
}}
|
||||
pageSizeOptions={[5]}
|
||||
/>
|
||||
</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} sx={{ marginTop:"2%"}}>
|
||||
<Card sx={{backgroundColor:portfolioBgColor}}>
|
||||
<Box sx={{textAlign:"center", paddingTop:"2%"}}>
|
||||
{(portfolioHeaderIsImage) ? (
|
||||
<img src={portfolioHeaderImageUrl} alt="Header Image" />
|
||||
) : (
|
||||
<Typography sx={{paddingBottom:"2%"}} variant={portfolioVariant} color={portfolioHeaderColor}>
|
||||
{portfolioHeaderText}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
</Box>
|
||||
{(portfolioShouldScroll)?(
|
||||
<CardContent sx={{height:`${portfolioSize}rem`, overflowY:"scroll",}}>
|
||||
{(profileData ? (
|
||||
<ArtistPortfolio masonry={portfolioWoven} columns={portfolioColumns} artistId={profileData["id"]} />
|
||||
):null)}
|
||||
</CardContent>
|
||||
):(
|
||||
<CardContent >
|
||||
{(profileData ? (
|
||||
<ArtistPortfolio masonry={portfolioWoven} columns={portfolioColumns} artistId={profileData["id"]} />
|
||||
):null)}
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid xs={12} md={12} sx={{ marginTop:"2%"}}>
|
||||
<Card sx={{backgroundColor:requestBgColor}}>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12} sx={{textAlign:"center"}}>
|
||||
{(requestHeaderIsImage) ? (
|
||||
<img src={requestHeaderImageUrl} alt="Header Image" />
|
||||
) : (
|
||||
<Typography sx={{paddingBottom:"2%"}} variant={requestVariant} color={requestHeaderColor}>
|
||||
{requestHeaderText}
|
||||
</Typography>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} sx={{textAlign:"center"}}>
|
||||
<Typography variant="body1" color={requestTermsTextColor}>
|
||||
TERMS
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} sx={{textAlign:"center"}}>
|
||||
<Typography color="white" variant="body2">By clicking the button below, you agree to the
|
||||
terms and conditions.</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} sx={{textAlign:"center"}}>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} sx={{textAlign:"center",paddingTop:"2%"}}>
|
||||
<Button size="large" variant="contained" sx={{backgroundColor:requestButtonBGColor, color:requestButtonTextColor,
|
||||
':hover': {
|
||||
bgcolor: requestHoverButtonBGColor, // theme.palette.primary.main
|
||||
color: requestHoverButtonTextColor,
|
||||
},}}>Agree And Start Request</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<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>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
// Protected route, checking user authentication client-side.(CSR)
|
||||
export default withPageAuthRequired(Profile);
|
||||
|
||||
|
||||
|
322
pages/dashboard/artist/requests.tsx
Normal file
322
pages/dashboard/artist/requests.tsx
Normal file
@ -0,0 +1,322 @@
|
||||
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, CardContent, IconButton, 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 X from '@mui/icons-material/X';
|
||||
import { Close, Upload } from '@mui/icons-material';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import dayjs from 'dayjs';
|
||||
import { useRouter } from 'next/router';
|
||||
import { ClipboardCheck, OpenInNew } from 'mdi-material-ui';
|
||||
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 { Card, CardHeader } from '@mui/material';
|
||||
import { Dialog, DialogActions, DialogContent, DialogTitle, Grid, Stack } from '@mui/material';
|
||||
import RequestReferenceImage from '../../../components/Old/requestReferencesImage';
|
||||
import RequestReferences from '../../../components/Old/requestReferences';
|
||||
|
||||
|
||||
export default function ServerPaginationGrid() {
|
||||
const router = useRouter();
|
||||
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="filled" color="success" />
|
||||
}
|
||||
else if(params.row.paid){
|
||||
return <Chip icon={<PriceCheckIcon />} label="Paid" variant="filled" color="success" />
|
||||
}
|
||||
else if(params.row.accepted && params.row.paid==false){
|
||||
return <Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="filled" color="warning" />
|
||||
}
|
||||
else if(params.row.accepted && params.row.paid){
|
||||
return <Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="filled" color="info" />
|
||||
}
|
||||
else if(params.row.declined){
|
||||
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="filled" color="error" />
|
||||
}
|
||||
else{
|
||||
return <Chip icon={<Refresh />} label="Pending" variant="filled" color="secondary" />
|
||||
}
|
||||
}
|
||||
},
|
||||
{ field: 'message', headerName: 'Message', flex: 0.5,
|
||||
renderCell: (params) => {
|
||||
return <TextField size="small" fullWidth value={params.row.message} disabled />;
|
||||
}},
|
||||
{ field: 'amount', headerName: 'Amount', flex: 0.1, renderCell: (params) => {
|
||||
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
|
||||
}},
|
||||
{ field: 'requestDate', headerName: 'Request Date', flex:0.15,
|
||||
renderCell: (params) =>{
|
||||
|
||||
let formattedTime = ""
|
||||
const date = new Date(params.row.requestDate);
|
||||
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
|
||||
return <DateField
|
||||
size='small'
|
||||
disabled
|
||||
defaultValue={dayjs(params.row.requestDate)}
|
||||
format="LL"
|
||||
/>
|
||||
} },
|
||||
{ field: 'action', headerName: '', flex:0.15,
|
||||
renderCell: (params) =>{
|
||||
|
||||
const acceptRequest = async () => {
|
||||
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/accept", { method: 'PUT' })
|
||||
if(response.status === 200){
|
||||
router.reload()
|
||||
}
|
||||
else{
|
||||
alert("Error accepting request.")
|
||||
}
|
||||
}
|
||||
|
||||
const viewRequest = async () => {
|
||||
|
||||
}
|
||||
|
||||
const denyRequest = async () => {
|
||||
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/deny", { method: 'PUT' })
|
||||
if(response.status === 200){
|
||||
router.reload()
|
||||
}
|
||||
else{
|
||||
alert("Error accepting request.")
|
||||
}
|
||||
}
|
||||
|
||||
const completeRequest = async () => {
|
||||
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/complete", { method: 'PUT' })
|
||||
if(response.status === 200){
|
||||
router.reload()
|
||||
}
|
||||
else{
|
||||
alert("Error accepting request.")
|
||||
}
|
||||
}
|
||||
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const handleClickOpen = () => {
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
let formattedTime = ""
|
||||
const date = new Date(params.row.requestDate);
|
||||
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
|
||||
|
||||
return (<>
|
||||
<Dialog
|
||||
fullWidth={true}
|
||||
maxWidth={"lg"}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<DialogTitle>Request submitted on {formattedTime ?? ''}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Grid container spacing={3} sx={{paddingTop:"1%"}}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<TextField
|
||||
multiline={true}
|
||||
rows={10}
|
||||
fullWidth
|
||||
label="Request Message"
|
||||
value={params.row.message}
|
||||
disabled
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12}>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Tooltip title="Decline this request.">
|
||||
<IconButton onClick={denyRequest} disabled={params.row.declined || params.row.accepted} color="error"><Close/></IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Accept this request.">
|
||||
<IconButton onClick={acceptRequest} disabled={params.row.declined || params.row.accepted} color="success"><Check/></IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Upload asset image for customer.">
|
||||
<IconButton disabled={!params.row.paid} color="primary"><Upload/></IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Complete this request.">
|
||||
<IconButton disabled={!params.row.paid || params.row.completed} color="success"><AssignmentTurnedInIcon/></IconButton>
|
||||
</Tooltip>
|
||||
{(!params.row.declined && !params.row.accepted && !params.row.paid && !params.row.completed ? (
|
||||
<Chip icon={<Refresh />} label="Pending" variant="filled" color="secondary" />
|
||||
):null)}
|
||||
{(params.row.declined ? (
|
||||
<Chip icon={<AssignmentLateIcon />} label="Declined" variant="filled" color="error" />
|
||||
):null)}
|
||||
{(params.row.accepted ? (
|
||||
<Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="filled" color="info" />
|
||||
):null)}
|
||||
{(params.row.paid ? (
|
||||
<Chip icon={<PriceCheckIcon />} label="Paid" variant="filled" color="success" />
|
||||
):null)}
|
||||
{(params.row.paid==false && params.row.accepted ? (
|
||||
<Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="filled" color="warning" />
|
||||
):null)}
|
||||
{(params.row.completed ? (
|
||||
<Chip disabled={!params.row.completed} icon={<Check />} label="Completed" variant="outlined" color="success" />
|
||||
):null)}
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12}>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose}>Close</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Tooltip title="View more details."><IconButton onClick={viewRequest} aria-label="accept" color="primary" onClick={handleClickOpen}><OpenInNew/></IconButton></Tooltip>
|
||||
{((params.row.accepted==false && params.row.declined==false && params.row.completed==false) ? (
|
||||
<>
|
||||
<Tooltip title="Accept this request.">
|
||||
<IconButton onClick={acceptRequest} aria-label="accept" color="success"><Check/></IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Deny this request.">
|
||||
<IconButton onClick={denyRequest} aria-label="deny" sx={{marginLeft:"2px"}} color="error"><Close/></IconButton>
|
||||
</Tooltip>
|
||||
</>
|
||||
): null
|
||||
)}
|
||||
{((params.row.accepted==true && params.row.declined==false && params.row.completed==false && params.row.paid==true) ? (
|
||||
<>
|
||||
<Tooltip title="Complete this request.">
|
||||
<IconButton onClick={completeRequest} aria-label="complete" color="success"><ClipboardCheck/></IconButton>
|
||||
</Tooltip>
|
||||
</>
|
||||
): null
|
||||
)}
|
||||
</>
|
||||
)
|
||||
} }
|
||||
];
|
||||
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 handlePageChange = async (params) => {
|
||||
setPaginationModel(params);
|
||||
}
|
||||
|
||||
const getRequests = async () => {
|
||||
setIsLoading(true);
|
||||
const response = await fetch('/api/artist/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/artist/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(() => {
|
||||
getRequestsCount();
|
||||
getRequests();
|
||||
}, [requestCount, setRowCountState,paginationModel]);
|
||||
|
||||
return (
|
||||
<div style={{ height: '100%', width: '100%' }}>
|
||||
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||
<DataGrid
|
||||
rows={requestData}
|
||||
columns={columns}
|
||||
rowCount={rowCountState}
|
||||
loading={isLoading}
|
||||
pageSizeOptions={[5]}
|
||||
paginationModel={paginationModel}
|
||||
paginationMode="server"
|
||||
onPaginationModelChange={handlePageChange}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -25,16 +25,19 @@ import router from 'next/router'
|
||||
import { isObject } from 'util'
|
||||
import Orders from '../../components/Orders'
|
||||
import StatisticsCard from '../../views/dashboard/StatisticsCard'
|
||||
import SellerStats from '../../components/SellerStats'
|
||||
import ArtistStats from '../../components/ArtistStats'
|
||||
import { Clipboard } from 'mdi-material-ui'
|
||||
import CircularProgress from '@mui/material/CircularProgress'
|
||||
import Box from '@mui/material/Box'
|
||||
|
||||
|
||||
|
||||
const Dashboard = () => {
|
||||
const [profileData, setSellerProfileData] = useState(null);
|
||||
const [requestData, setSellerRequestData] = useState(null);
|
||||
const [profileData, setArtistData] = useState(null);
|
||||
const [requestData, setArtistRequestData] = useState(null);
|
||||
const [onboardData, setOnboardedData] = useState(false);
|
||||
|
||||
const [statsData, setStatsData] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [onboarding, setOnboarding] = useState(false);
|
||||
const [onboarded, setOnboarded] = useState(false);
|
||||
|
||||
@ -45,10 +48,13 @@ const Dashboard = () => {
|
||||
const getData = async () => {
|
||||
const profileResponse = await fetch('/api/artist/profile');
|
||||
const sellerProfile = await profileResponse.json();
|
||||
setSellerProfileData(sellerProfile);
|
||||
setArtistData(sellerProfile);
|
||||
const statsResponse = await fetch('/api/artist/stats');
|
||||
const statsResponseData = await statsResponse.json();
|
||||
setStatsData(statsResponseData);
|
||||
const requestResponse = await fetch('/api/artist/request');
|
||||
const sellerRequest = await requestResponse.json();
|
||||
setSellerRequestData(sellerRequest);
|
||||
setArtistRequestData(sellerRequest);
|
||||
const onboardedResponse = await fetch('/api/artist/onboarded');
|
||||
const onboardedData = await onboardedResponse.json();
|
||||
setOnboardedData(onboardedData["onboarded"]);
|
||||
@ -59,94 +65,108 @@ const Dashboard = () => {
|
||||
setOnboarding(true)
|
||||
}
|
||||
if(sellerProfile!=null && Object.keys(sellerProfile).length>0 && sellerRequest["accepted"]){
|
||||
////console.log("Test")
|
||||
setOnboarded(true)
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
{(loading) ? (
|
||||
<Box sx={{textAlign:"center", paddingTop:"20%"}}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
):(
|
||||
|
||||
|
||||
<ApexChartWrapper>
|
||||
<Grid container spacing={6}>
|
||||
<Grid container spacing={6}>
|
||||
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={3} sx={{textAlign:"center"}}>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
My Orders
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4} sx={{textAlign:"center"}}>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={5} sx={{textAlign:"center"}}>
|
||||
<Button color="info" onClick={()=>{router.push("/dashboard/orders")}} fullWidth variant="contained">View All Orders</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} sx={{paddingTop:"2%"}}>
|
||||
<Orders />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={3} sx={{textAlign:"center"}}>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
Requests
|
||||
</Typography>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4} sx={{textAlign:"center"}}>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={5} sx={{textAlign:"center"}}>
|
||||
<Button color="info" onClick={()=>{router.push("/dashboard/requests")}} fullWidth variant="contained">View All Requests</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} sx={{paddingTop:"2%"}}>
|
||||
<Orders />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
|
||||
{( onboarding==true && onboardData==false ) ? (
|
||||
<Grid item xs={12} md={6}>
|
||||
<Onboarding />
|
||||
</Grid>
|
||||
):(
|
||||
(onboarding) ? (
|
||||
<Grid item xs={12} md={6}>
|
||||
|
||||
{( onboarding==true && onboarded==false || onboardData==false ) ? (
|
||||
<Grid item xs={12} md={6}>
|
||||
<Onboarding />
|
||||
</Grid>
|
||||
):(
|
||||
(onboarded && onboardData==true && onboarding) ? (
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card sx={{textAlign:"center", width:"100%"}}>
|
||||
<CardContent>
|
||||
<Grid spacing={3} container>
|
||||
<Grid item xs={12} md={12} >
|
||||
{(statsData!=null && isObject(statsData)) ? (<ArtistStats profileData={profileData} stats={statsData} />
|
||||
):(
|
||||
null
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12} md={8}>
|
||||
<TextField size="small" label="Your Public URL" variant="outlined" disabled fullWidth defaultValue={"http://localhost:3000/box/"+profileData["name"].replace(/\s+/g, '-') ?? ""}>http://localhost:3000/box/"{(profileData["name"].replace(/\s+/g, '-') ?? "")}</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2}>
|
||||
<Button color="info" startIcon={<Clipboard/>} onClick={()=>{router.push("/dashboard/artist/artistsettings#portfolio")}} fullWidth variant="outlined">Copy</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2}>
|
||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/artistsettings#portfolio")}} fullWidth variant="outlined">Preview</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/artistsettings#portfolio")}} fullWidth variant="contained">Manage Portfolio</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/pagesettings")}} fullWidth variant="contained">Design Store Page</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/pagesettings")}} fullWidth variant="contained">Payment Portal</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/artistsettings")}} fullWidth variant="contained">Configure Your Shop</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
) : (
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card sx={{textAlign:"center", width:"100%"}}>
|
||||
<CardContent>
|
||||
<Grid spacing={3} container>
|
||||
<Grid item xs={12} md={12} >
|
||||
<SellerStats />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={8}>
|
||||
<TextField size="small" label="Your Public URL" variant="outlined" disabled fullWidth defaultValue={"http://localhost:3000/shops/neroshi"}>"http://localhost:3000/shops/neroshi"</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2}>
|
||||
<Button color="info" startIcon={<Clipboard/>} onClick={()=>{router.push("/dashboard/artist/artistsettings#portfolio")}} fullWidth variant="outlined">Copy</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={2}>
|
||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/artistsettings#portfolio")}} fullWidth variant="outlined">Preview</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/artistsettings#portfolio")}} fullWidth variant="contained">Manage Portfolio</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/pagesettings")}} fullWidth variant="contained">Design Store Page</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/pagesettings")}} fullWidth variant="contained">Payment Portal</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/pagesettings")}} fullWidth variant="contained">Configure Your Shop</Button>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Button color="primary" fullWidth variant="contained" onClick={setOnboardingTrue}>Become An Artist</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
) : (
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card sx={{textAlign:"center", width:"100%"}}>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Button color="primary" fullWidth variant="contained" onClick={setOnboardingTrue}>Become An Artist</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
)
|
||||
)}
|
||||
</Grid>
|
||||
</ApexChartWrapper>
|
||||
)
|
||||
)}
|
||||
</Grid>
|
||||
</ApexChartWrapper>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
63
pages/dashboard/payout.tsx
Normal file
63
pages/dashboard/payout.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
||||
import { CardHeader, Grid, Typography } from "@mui/material";
|
||||
import Card from "@mui/material/Card";
|
||||
import CardContent from "@mui/material/CardContent";
|
||||
import { useEffect, useState } from "react";
|
||||
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
|
||||
import Button from '@mui/material/Button';
|
||||
import { OpenInNew } from "@mui/icons-material";
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
const Payout = () => {
|
||||
const {user, isLoading} = useUser();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [payoutData, setPayoutData] = useState(null);
|
||||
const getData = async () => {
|
||||
var payoutResponse = await fetch('/api/artist/payout');
|
||||
var payoutData = await payoutResponse.json();
|
||||
setPayoutData(payoutData);
|
||||
setLoading(false);
|
||||
}
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
{(loading) ? (
|
||||
<Box sx={{textAlign:"center", paddingTop:"20%"}}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
):(
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={4}>
|
||||
<Card>
|
||||
<CardHeader title="Payout Settings" />
|
||||
<CardContent>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={4}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12}>
|
||||
<CurrencyTextField fullWidth label="Current Balance" size="large" disabled variant="standard" currencySymbol="$" outputFormat="string" decimalCharacter="." digitGroupSeparator="," value={payoutData ? payoutData["balance"] : ""} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<CurrencyTextField fullWidth label="Pending Balance" size="large" disabled variant="standard" currencySymbol="$" outputFormat="string" decimalCharacter="." digitGroupSeparator="," value={payoutData ? payoutData["pendingBalance"] : ""} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={8}>
|
||||
<Button fullWidth href={payoutData ? payoutData["payoutUrl"] : ""} target="_blank" startIcon={<OpenInNew/>} variant="contained" color="info" size="large">Open Dashboard</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// Protected route, checking user authentication client-side.(CSR)
|
||||
export default withPageAuthRequired(Payout);
|
310
pages/dashboard/requests.tsx
Normal file
310
pages/dashboard/requests.tsx
Normal file
@ -0,0 +1,310 @@
|
||||
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 {Check, Close, Download, OpenInFull, OpenInNew, Refresh, 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 dayjs from 'dayjs';
|
||||
import { DownloadBox } from 'mdi-material-ui';
|
||||
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material';
|
||||
import RequestDialog from '../../components/requestDialog';
|
||||
import { Grid } from '@mui/material';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
|
||||
export default function ServerPaginationGrid() {
|
||||
const router = useRouter();
|
||||
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="filled" color="success" />
|
||||
}
|
||||
else if(params.row.paid){
|
||||
return <Chip icon={<PriceCheckIcon />} label="Paid" variant="filled" color="success" />
|
||||
}
|
||||
else if(params.row.accepted && params.row.paid==false){
|
||||
return <Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="filled" color="warning" />
|
||||
}
|
||||
else if(params.row.accepted && params.row.paid){
|
||||
return <Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="filled" color="info" />
|
||||
}
|
||||
else if(params.row.declined){
|
||||
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="filled" color="error" />
|
||||
}
|
||||
else{
|
||||
return <Chip icon={<Refresh />} label="Pending" variant="filled" color="secondary" />
|
||||
}
|
||||
}
|
||||
},
|
||||
{ field: 'message', headerName: 'Message', flex: 0.5,
|
||||
renderCell: (params) => {
|
||||
return <TextField size="small" fullWidth value={params.row.message} disabled />;
|
||||
}},
|
||||
{ field: 'amount', headerName: 'Amount', flex: 0.1, renderCell: (params) => {
|
||||
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
|
||||
}},
|
||||
{ field: 'requestDate', headerName: 'Request Date', flex:0.15,
|
||||
renderCell: (params) =>{
|
||||
|
||||
let formattedTime = ""
|
||||
const date = new Date(params.row.requestDate);
|
||||
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
|
||||
return <DateField
|
||||
size='small'
|
||||
disabled
|
||||
defaultValue={dayjs(params.row.requestDate)}
|
||||
format="LL"
|
||||
/>
|
||||
} },
|
||||
{ field: 'download', headerName: '', flex:0.1,
|
||||
renderCell: (params) =>{
|
||||
const acceptRequest = async () => {
|
||||
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/accept", { method: 'PUT' })
|
||||
if(response.status === 200){
|
||||
router.reload()
|
||||
}
|
||||
else{
|
||||
alert("Error accepting request.")
|
||||
}
|
||||
}
|
||||
|
||||
const viewRequest = async () => {
|
||||
|
||||
}
|
||||
|
||||
const denyRequest = async () => {
|
||||
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/deny", { method: 'PUT' })
|
||||
if(response.status === 200){
|
||||
router.reload()
|
||||
}
|
||||
else{
|
||||
alert("Error accepting request.")
|
||||
}
|
||||
}
|
||||
|
||||
const completeRequest = async () => {
|
||||
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/complete", { method: 'PUT' })
|
||||
if(response.status === 200){
|
||||
router.reload()
|
||||
}
|
||||
else{
|
||||
alert("Error accepting request.")
|
||||
}
|
||||
}
|
||||
const handlePay = async () => {
|
||||
var paymentUrlRequest = await fetch('/api/requests/'+params.row.id+'/payment')
|
||||
//console.log(paymentUrlRequest);
|
||||
var paymentUrlJson = await paymentUrlRequest.json();
|
||||
var paymentUrl = paymentUrlJson.paymentUrl;
|
||||
window.open(paymentUrl);
|
||||
}
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const handleClickOpen = () => {
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
let formattedTime = ""
|
||||
const date = new Date(params.row.requestDate);
|
||||
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
|
||||
|
||||
return (<>
|
||||
<Dialog
|
||||
fullWidth={true}
|
||||
maxWidth={"lg"}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<DialogTitle>Request submitted on {formattedTime ?? ''}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Grid container spacing={3} sx={{paddingTop:"1%"}}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<TextField
|
||||
multiline={true}
|
||||
rows={10}
|
||||
fullWidth
|
||||
label="Request Message"
|
||||
value={params.row.message}
|
||||
disabled
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12}>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Tooltip title="Upload reference image.">
|
||||
<IconButton disabled={params.row.accepted && params.row.paid} color="primary"><Upload/></IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Pay for this request.">
|
||||
<IconButton onClick={handlePay} disabled={params.row.accepted && params.row.paid || params.row.declined} color="success"><ShoppingCartCheckoutIcon/></IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Download all assets.">
|
||||
<IconButton disabled={!params.row.completed} color="secondary"><Download/></IconButton>
|
||||
</Tooltip>
|
||||
{(!params.row.declined && !params.row.accepted && !params.row.paid && !params.row.completed ? (
|
||||
<Chip icon={<Refresh />} label="Pending" variant="filled" color="secondary" />
|
||||
):null)}
|
||||
{(params.row.declined ? (
|
||||
<Chip icon={<AssignmentLateIcon />} label="Declined" variant="filled" color="error" />
|
||||
):null)}
|
||||
{(params.row.accepted ? (
|
||||
<Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="filled" color="info" />
|
||||
):null)}
|
||||
{(params.row.paid && params.row.acccepted ? (
|
||||
<Chip label="Paid" variant="filled" color="success" />
|
||||
):null)}
|
||||
{(params.row.paid==false && params.row.accepted ? (
|
||||
<Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="filled" color="warning" />
|
||||
):null)}
|
||||
{(params.row.completed ? (
|
||||
<Chip disabled={!params.row.completed} icon={<Check />} label="Completed" variant="outlined" color="success" />
|
||||
):null)}
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12}>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose}>Close</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Tooltip title="View more details."><IconButton onClick={handleClickOpen} aria-label="accept" color="primary"><OpenInNew/></IconButton></Tooltip>
|
||||
{((params.row.accepted==true &¶ms.row.declined==false && params.row.paid==false) ? (
|
||||
<Tooltip title="Pay for this request."><IconButton onClick={handlePay} aria-label="accept" color="success"><ShoppingCartCheckoutIcon/></IconButton></Tooltip>
|
||||
): null
|
||||
)}
|
||||
{((params.row.completed) ? (
|
||||
<Tooltip title="Download requests assets."><IconButton aria-label="download" color="secondary"><Download/></IconButton></Tooltip>
|
||||
): null
|
||||
)}
|
||||
</>
|
||||
)
|
||||
} }
|
||||
];
|
||||
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={{ height: '100%', width: '100%' }}>
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||
<DataGrid
|
||||
rows={requestData}
|
||||
columns={columns}
|
||||
rowCount={rowCountState}
|
||||
loading={isLoading}
|
||||
pageSizeOptions={[5]}
|
||||
paginationModel={paginationModel}
|
||||
paginationMode="server"
|
||||
onPaginationModelChange={setPaginationModel}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
280
pages/dashboard/requests/[requestId].tsx
Normal file
280
pages/dashboard/requests/[requestId].tsx
Normal file
@ -0,0 +1,280 @@
|
||||
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/Old/artistPortfolio";
|
||||
import { RouterNetwork } from "mdi-material-ui";
|
||||
import { useRouter } from "next/router";
|
||||
import { profile } from "console";
|
||||
|
||||
const Profile = () => {
|
||||
|
||||
const [profileData, setArtistData] = useState(null);
|
||||
const [description, setDescription] = useState("");
|
||||
const [guidelines, setGuidelines] = useState("");
|
||||
|
||||
const [requestMessage, setRequestMessage] = useState("");
|
||||
const [requestPrice, setRequestPrice] = useState(100.00);
|
||||
|
||||
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 () => {
|
||||
var payload = JSON.stringify({
|
||||
"artistId": profileData["id"],
|
||||
"message": requestMessage,
|
||||
"amount": requestPrice
|
||||
});
|
||||
//console.log(payload)
|
||||
const requestResponse = await fetch('/api/box/newRequest', {
|
||||
method: 'POST',
|
||||
body: payload
|
||||
})
|
||||
if(requestResponse.ok){
|
||||
router.push("/dashboard/requests")
|
||||
}
|
||||
else{
|
||||
alert("Error submitting request")
|
||||
}
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
const columns: GridColDef[] = [
|
||||
{
|
||||
field: 'message',
|
||||
headerName: 'Review',
|
||||
flex: 0.75
|
||||
},
|
||||
{
|
||||
field: 'rating',
|
||||
headerName: 'Rating',
|
||||
flex: 0.25,
|
||||
renderCell: (params: GridValueGetterParams) => (
|
||||
<Rating name="read-only" value={params.value} readOnly />
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const rows = [
|
||||
{ id: 1, message: 'Great work!', rating: 5 },
|
||||
{ id: 2, message: 'BAD work!', rating: 1 },
|
||||
{ id: 3, message: 'Okay work!', rating: 4 },
|
||||
{ id: 4, message: 'Meh work!', rating: 2 },
|
||||
{ id: 5, message: 'Great work!', rating: 5 },
|
||||
{ id: 6, message: 'Mid work!', rating: 3 },
|
||||
{ id: 7, message: 'HORRIBLE work!', rating: 1 },
|
||||
];
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
PaperProps={{
|
||||
component: 'form',
|
||||
onSubmit: (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
const formData = new FormData(event.currentTarget);
|
||||
const formJson = Object.fromEntries((formData as any).entries());
|
||||
const email = formJson.email;
|
||||
////console.log(email);
|
||||
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="name"
|
||||
name="message"
|
||||
label="Request Message"
|
||||
type="message"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
multiline
|
||||
rows={10}
|
||||
onChange={handleRequestMessageChange}
|
||||
value={requestMessage}
|
||||
/>
|
||||
<CurrencyTextField
|
||||
label="Price"
|
||||
variant="standard"
|
||||
currencySymbol="$"
|
||||
outputFormat="number"
|
||||
decimalCharacter="."
|
||||
digitGroupSeparator=","
|
||||
fullWidth
|
||||
onChange={handleRequestPriceChange}
|
||||
value={requestPrice}/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose}>Cancel</Button>
|
||||
<Button onClick={submitRequest} 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} >
|
||||
<DataGrid
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
autoHeight={true}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: {
|
||||
pageSize: 5,
|
||||
},
|
||||
},
|
||||
}}
|
||||
pageSizeOptions={[5]}
|
||||
/>
|
||||
</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(Profile);
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { useUser, withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
||||
import { Grid, Typography } from "@mui/material";
|
||||
import { CircularProgress, Grid, Typography } from "@mui/material";
|
||||
import { useEffect, useState } from "react";
|
||||
import Card from "@mui/material/Card";
|
||||
import CardContent from "@mui/material/CardContent";
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Button from '@mui/material/Button';
|
||||
import Box from '@mui/material/Box';
|
||||
import * as React from 'react';
|
||||
|
||||
|
||||
const ArtistSettings = () => {
|
||||
@ -14,6 +16,9 @@ const ArtistSettings = () => {
|
||||
const [biography, setBiography] = useState("");
|
||||
const [saved, setSaved] = useState(false);
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
|
||||
const handleDisplayNameChange = (event) => {
|
||||
setDisplayName(event.target.value);
|
||||
}
|
||||
@ -41,8 +46,15 @@ const ArtistSettings = () => {
|
||||
setDisplayName(user["displayName"])
|
||||
setBiography(user["biography"])
|
||||
setAppUser(user);
|
||||
setLoading(false);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{(loading) ? (
|
||||
<Box sx={{textAlign:"center"}}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
):(
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card>
|
||||
@ -61,14 +73,13 @@ const ArtistSettings = () => {
|
||||
<Grid item xs={12} md={12} sx={{ paddingTop: "2%" }}>
|
||||
<TextField id="outlined-basic" label="Display Name" onChange={handleDisplayNameChange} variant="outlined" fullWidth value={displayName} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} sx={{ paddingTop: "2%" }}>
|
||||
<TextField id="outlined-basic" multiline rows={5} label="Biography" onChange={handleBiographyChange} variant="outlined" value={biography} fullWidth />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -15,7 +15,8 @@ import Pricing from '../components/Pricing';
|
||||
import BetaAccess from '../components/BetaAccess';
|
||||
import FAQ from '../components/FAQ';
|
||||
import Footer from '../components/Footer';
|
||||
import { useUser } from "@auth0/nextjs-auth0/client";
|
||||
import { useUser, } from "@auth0/nextjs-auth0/client";
|
||||
import { getSession } from "@auth0/nextjs-auth0";
|
||||
const defaultTheme = createTheme({});
|
||||
|
||||
interface ToggleCustomThemeProps {
|
||||
@ -68,11 +69,7 @@ export default function LandingPage() {
|
||||
const [showCustomTheme, setShowCustomTheme] = React.useState(true);
|
||||
|
||||
const { user, isLoading } = useUser();
|
||||
|
||||
const toggleCustomTheme = () => {
|
||||
setShowCustomTheme((prev) => !prev);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={defaultTheme}>
|
||||
<CssBaseline />
|
||||
|
@ -3,9 +3,9 @@
|
||||
|
||||
|
||||
|
||||
export async function fetchSellerPortfolio(id): Promise<any> {
|
||||
export async function fetchArtistPortfolio(id): Promise<any> {
|
||||
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${id}/Portfolio`;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${id}/Portfolio`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch seller portfolio');
|
||||
@ -15,7 +15,7 @@ export async function fetchSellerPortfolio(id): Promise<any> {
|
||||
|
||||
export async function fetchServicePortfolio(sellerId, serviceId): Promise<any> {
|
||||
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${sellerId}/Services/${serviceId}/Portfolio`;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}/Services/${serviceId}/Portfolio`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch seller portfolio');
|
||||
@ -25,7 +25,7 @@ export async function fetchServicePortfolio(sellerId, serviceId): Promise<any> {
|
||||
|
||||
export async function fetchService(sellerId, serviceId): Promise<any> {
|
||||
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${sellerId}/Services/${serviceId}`;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}/Services/${serviceId}`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch seller portfolio');
|
||||
@ -36,6 +36,6 @@ export async function fetchService(sellerId, serviceId): Promise<any> {
|
||||
|
||||
export function getPortfolioUrl(id, pieceId): string {
|
||||
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Sellers/${id}/Portfolio/${pieceId}`;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${id}/Portfolio/${pieceId}`;
|
||||
return url;
|
||||
}
|
2555
swagger.json
2555
swagger.json
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user