mirror of
https://github.com/D4M13N-D3V/comissions-app-ui.git
synced 2025-03-13 07:45:07 +00:00
feat: rating/reviews
This commit is contained in:
parent
238477665d
commit
aac4ec902f
@ -85,7 +85,7 @@ const ArtistStats = ({profileData, stats}) => {
|
|||||||
/>
|
/>
|
||||||
<CardContent sx={{ pt: theme => `${theme.spacing(3)} !important` }}>
|
<CardContent sx={{ pt: theme => `${theme.spacing(3)} !important` }}>
|
||||||
<Grid container spacing={[5, 0]}>
|
<Grid container spacing={[5, 0]}>
|
||||||
<Grid item xs={12} sm={3}>
|
<Grid item xs={6} sm={3}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<Avatar
|
<Avatar
|
||||||
variant='rounded'
|
variant='rounded'
|
||||||
@ -106,7 +106,7 @@ const ArtistStats = ({profileData, stats}) => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={3}>
|
<Grid item xs={6} sm={3}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<Avatar
|
<Avatar
|
||||||
variant='rounded'
|
variant='rounded'
|
||||||
@ -127,7 +127,7 @@ const ArtistStats = ({profileData, stats}) => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={3}>
|
<Grid item xs={6} sm={3}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<Avatar
|
<Avatar
|
||||||
variant='rounded'
|
variant='rounded'
|
||||||
@ -148,7 +148,7 @@ const ArtistStats = ({profileData, stats}) => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={3}>
|
<Grid item xs={6} sm={3}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<Avatar
|
<Avatar
|
||||||
variant='rounded'
|
variant='rounded'
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import Card from '@mui/material/Card';
|
|
||||||
import CardActions from '@mui/material/CardActions';
|
|
||||||
import CardContent from '@mui/material/CardContent';
|
|
||||||
import Typography from '@mui/material/Typography';
|
|
||||||
import CardMedia from '@mui/material/CardMedia';
|
|
||||||
import StarBorderOutlinedIcon from '@mui/icons-material/StarBorderOutlined';
|
|
||||||
import ShoppingCartCheckoutOutlinedIcon from '@mui/icons-material/ShoppingCartCheckoutOutlined';
|
|
||||||
import AccountCircleOutlinedIcon from '@mui/icons-material/AccountCircleOutlined';
|
|
||||||
import Grid from '@mui/material/Grid';
|
|
||||||
import Item from '@mui/material/Grid';
|
|
||||||
import Accordion from '@mui/material/Accordion';
|
|
||||||
import AccordionSummary from '@mui/material/AccordionSummary';
|
|
||||||
import AccordionDetails from '@mui/material/AccordionDetails';
|
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
||||||
import ArtistPortfolio from './artistPortfolio';
|
|
||||||
import Button from '@mui/material/Button';
|
|
||||||
import Tooltip from '@mui/material/Tooltip';
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
|
|
||||||
import { IconButton } from '@mui/material';
|
|
||||||
|
|
||||||
const Artist = ({user, artistId}) => {
|
|
||||||
const [sellerData, setArtistData] = useState([]);
|
|
||||||
useEffect(() => {
|
|
||||||
const getData = async () => {
|
|
||||||
const response = await fetch('/api/discovery/artist/'+artistId);
|
|
||||||
const data = await response.json();
|
|
||||||
setArtistData(data);
|
|
||||||
}
|
|
||||||
getData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card color="primary" sx={{margin:5}}>
|
|
||||||
<CardContent>
|
|
||||||
<Grid container spacing={2}>
|
|
||||||
<Grid item xs={6} md={8}>
|
|
||||||
<Item>
|
|
||||||
<Typography variant="h5" component="h2">
|
|
||||||
{sellerData["name"]}
|
|
||||||
</Typography>
|
|
||||||
<Typography color="primary">
|
|
||||||
{sellerData["averageRating"] ? `${sellerData["averageRating"]} Stars (${sellerData["reviewCount"]} Reviews)` : "No Reviews"}
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="body2" component="p">
|
|
||||||
{sellerData["biography"]}
|
|
||||||
</Typography>
|
|
||||||
</Item>
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={6} md={4}>
|
|
||||||
<Grid item xs={6} md={4}>
|
|
||||||
<Button href={"artist/"+artistId} color="primary" variant='contained' sx={{width:160}}>View Profile</Button>
|
|
||||||
{user ? (
|
|
||||||
<Button color="secondary" variant='contained' href={"/artist/"+artistId+"/request"} sx={{ width: 160, marginTop:2 }}>Submit Request</Button>
|
|
||||||
) : (
|
|
||||||
<Tooltip title="Log in order to place a request.">
|
|
||||||
<span>
|
|
||||||
<Button disabled color="secondary" variant='contained' sx={{ width: 160, marginTop:2 }}>Submit Request</Button>
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} md={12}>
|
|
||||||
|
|
||||||
<Item>
|
|
||||||
</Item>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</CardContent>
|
|
||||||
</Card>)
|
|
||||||
}
|
|
||||||
export default Artist
|
|
@ -1,139 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { useUser } from "@auth0/nextjs-auth0/client";
|
|
||||||
import AppBar from '@mui/material/AppBar';
|
|
||||||
import Box from '@mui/material/Box';
|
|
||||||
import Toolbar from '@mui/material/Toolbar';
|
|
||||||
import Typography from '@mui/material/Typography';
|
|
||||||
import Menu from '@mui/material/Menu';
|
|
||||||
import Container from '@mui/material/Container';
|
|
||||||
import Button from '@mui/material/Button';
|
|
||||||
import MenuItem from '@mui/material/MenuItem';
|
|
||||||
import { Chip, Icon } from '@mui/material';
|
|
||||||
import {
|
|
||||||
NovuProvider,
|
|
||||||
PopoverNotificationCenter,
|
|
||||||
NotificationBell,
|
|
||||||
} from '@novu/notification-center';
|
|
||||||
|
|
||||||
|
|
||||||
type HeaderProps = {
|
|
||||||
user?: any;
|
|
||||||
loading: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const settings = ['Artist Dashboard', 'Account', 'Dashboard', 'Logout'];
|
|
||||||
|
|
||||||
function ResponsiveAppBar() {
|
|
||||||
const [anchorElNav, setAnchorElNav] = React.useState<null | HTMLElement>(null);
|
|
||||||
const [anchorElUser, setAnchorElUser] = React.useState<null | HTMLElement>(null);
|
|
||||||
|
|
||||||
const handleOpenNavMenu = (event: React.MouseEvent<HTMLElement>) => {
|
|
||||||
setAnchorElNav(event.currentTarget);
|
|
||||||
};
|
|
||||||
const handleOpenUserMenu = (event: React.MouseEvent<HTMLElement>) => {
|
|
||||||
setAnchorElUser(event.currentTarget);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCloseNavMenu = () => {
|
|
||||||
setAnchorElNav(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCloseUserMenu = () => {
|
|
||||||
setAnchorElUser(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const { user, isLoading } = useUser();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AppBar color="primary" position="static">
|
|
||||||
<Container maxWidth="xl">
|
|
||||||
<Toolbar disableGutters>
|
|
||||||
<Box sx={{ flex:1, textAlign:"center" }}>
|
|
||||||
<Typography
|
|
||||||
href="/"
|
|
||||||
variant="h6"
|
|
||||||
noWrap
|
|
||||||
color="secondary"
|
|
||||||
component="a"
|
|
||||||
sx={{
|
|
||||||
mr: 2,
|
|
||||||
paddingLeft: '1rem',
|
|
||||||
display: { xs: 'flex', md: 'flex' },
|
|
||||||
fontFamily: 'monospace',
|
|
||||||
fontWeight: 700,
|
|
||||||
letterSpacing: '0rem',
|
|
||||||
textDecoration: 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
REQUEST.BOX
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{
|
|
||||||
user ? (
|
|
||||||
<>
|
|
||||||
<Box>
|
|
||||||
<NovuProvider subscriberId={'on-boarding-subscriber-id-123'} applicationIdentifier={'9SKjzgN_odAF'}>
|
|
||||||
<PopoverNotificationCenter colorScheme={'light'}>
|
|
||||||
{({ unseenCount }) => <NotificationBell unseenCount={unseenCount} />}
|
|
||||||
</PopoverNotificationCenter>
|
|
||||||
</NovuProvider>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Chip
|
|
||||||
onClick={handleOpenUserMenu}
|
|
||||||
label={user.name}
|
|
||||||
color="secondary"
|
|
||||||
variant={'outlined'}
|
|
||||||
style={{ marginLeft: '10px', minWidth: '5rem', maxWidth:'10rem' }}
|
|
||||||
/>
|
|
||||||
<Menu
|
|
||||||
sx={{ mt: '45px' }}
|
|
||||||
id="menu-appbar"
|
|
||||||
anchorEl={anchorElUser}
|
|
||||||
anchorOrigin={{
|
|
||||||
vertical: 'top',
|
|
||||||
horizontal: 'right',
|
|
||||||
}}
|
|
||||||
keepMounted
|
|
||||||
transformOrigin={{
|
|
||||||
vertical: 'top',
|
|
||||||
horizontal: 'right',
|
|
||||||
}}
|
|
||||||
open={Boolean(anchorElUser)}
|
|
||||||
onClose={handleCloseUserMenu}
|
|
||||||
>
|
|
||||||
<MenuItem key="artistDashboard" onClick={handleCloseUserMenu}>
|
|
||||||
<Button fullWidth color="secondary" variant='contained' href="/artistDashboard">Artist Dashboard</Button>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="myOrders" onClick={handleCloseUserMenu}>
|
|
||||||
<Button fullWidth color="primary" href="profile">My Orders</Button>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="settings" onClick={handleCloseUserMenu}>
|
|
||||||
<Button fullWidth color="primary" href="/settings">Settings</Button>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="logout" onClick={handleCloseUserMenu}>
|
|
||||||
<Button fullWidth color="error" href="/api/auth/logout">Logout</Button>
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Button key="login" href='/api/auth/login' onClick={handleCloseNavMenu} sx={{ my: 2, display: 'block', color:"white" }}>
|
|
||||||
Login
|
|
||||||
</Button>
|
|
||||||
<Button key="signup" href='/api/auth/login' onClick={handleCloseNavMenu} sx={{ my: 2, display: 'block', color:"white" }}>
|
|
||||||
Signup
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
|
|
||||||
)}
|
|
||||||
|
|
||||||
</Toolbar>
|
|
||||||
</Container>
|
|
||||||
</AppBar>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export default ResponsiveAppBar;
|
|
@ -1,41 +0,0 @@
|
|||||||
import Head from "next/head";
|
|
||||||
import Header from "../header";
|
|
||||||
|
|
||||||
type LayoutProps = {
|
|
||||||
user?: any;
|
|
||||||
loading?: boolean;
|
|
||||||
children: React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Layout = ({ user, loading = false, children }: LayoutProps) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>comissions.app</title>
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<Header user={user} loading={loading} />
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div className="container">{children}</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<style jsx>{`
|
|
||||||
.container {
|
|
||||||
max-width: 82rem;
|
|
||||||
margin: 1.5rem auto;
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
<style jsx global>{`
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
color: #333;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
||||||
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Layout;
|
|
@ -1,31 +0,0 @@
|
|||||||
import { useEffect, useRef } from "react"
|
|
||||||
|
|
||||||
export default function SwipeableViews(
|
|
||||||
{ className = "", index, onChangeIndex, ...rootProps }:
|
|
||||||
{ index: number, onChangeIndex: (index: number) => void } & React.HTMLProps<HTMLDivElement>
|
|
||||||
) {
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
|
||||||
const scrollTimeout = useRef<number>()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
containerRef.current?.children[index]?.scrollIntoView({ behavior: "smooth" })
|
|
||||||
}, [index])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
{...rootProps}
|
|
||||||
ref={containerRef}
|
|
||||||
className={
|
|
||||||
"flex snap-x snap-mandatory items-stretch overflow-x-scroll " +
|
|
||||||
"*:w-full *:flex-shrink-0 *:snap-center " + className
|
|
||||||
}
|
|
||||||
onScroll={({ currentTarget }) => {
|
|
||||||
if (scrollTimeout.current) clearTimeout(scrollTimeout.current)
|
|
||||||
scrollTimeout.current = window.setTimeout(() => {
|
|
||||||
const pageWidth = currentTarget.scrollWidth / currentTarget.children.length
|
|
||||||
onChangeIndex(Math.round(currentTarget.scrollLeft / pageWidth))
|
|
||||||
}, 100)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
@ -44,19 +44,8 @@ export default function ServerPaginationGrid() {
|
|||||||
{ field: 'amount', headerName: 'Amount', flex: 0.1, renderCell: (params) => {
|
{ field: 'amount', headerName: 'Amount', flex: 0.1, renderCell: (params) => {
|
||||||
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
|
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
|
||||||
}},
|
}},
|
||||||
{ field: 'requestDate', headerName: 'Request Date', flex:0.15,
|
{ field: 'requestDate', headerName: 'Request Date', flex:0.15, type: 'date' ,
|
||||||
renderCell: (params) =>{
|
valueGetter: (params) => { return new Date(params.row.requestDate); }}
|
||||||
|
|
||||||
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 [isLoading, setIsLoading] = React.useState(true);
|
||||||
const [requestCount, setRequestCount] = React.useState(null);
|
const [requestCount, setRequestCount] = React.useState(null);
|
||||||
|
143
components/RequestDialog.tsx
Normal file
143
components/RequestDialog.tsx
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { DataGrid, GridToolbar } from '@mui/x-data-grid';
|
||||||
|
import { GridColDef } from '@mui/x-data-grid';
|
||||||
|
import { Button, Stack, Typography } from '@mui/material';
|
||||||
|
import { Chip, IconButton, Tooltip } from '@mui/material';
|
||||||
|
import { AssignmentLateOutlined, AssignmentTurnedInOutlined, Check, Download, PriceCheck, PriceCheckOutlined, Refresh, ShoppingCartCheckout } from '@mui/icons-material';
|
||||||
|
import { Card, CardContent } from '@mui/material';
|
||||||
|
import Rating from '@mui/material/Rating';
|
||||||
|
import { Dialog, DialogTitle, DialogContent, DialogActions, Grid, TextField } from '@mui/material';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
export default function RequestDialog() {
|
||||||
|
|
||||||
|
|
||||||
|
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={6}>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={12} md={3}>
|
||||||
|
<Tooltip arrow title="Pay for this request.">
|
||||||
|
<IconButton onClick={handlePay} disabled={params.row.accepted && params.row.paid || params.row.declined} color="success"><ShoppingCartCheckoutIcon/></IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={3}>
|
||||||
|
<Tooltip arrow title="Download all assets.">
|
||||||
|
<IconButton disabled={!params.row.completed} color="secondary"><Download/></IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<Grid container spacing={1}>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
|
{(!params.row.declined && !params.row.accepted && !params.row.paid && !params.row.completed ? (
|
||||||
|
<Chip icon={<Refresh />} label="Pending" variant="filled" color="secondary" />
|
||||||
|
):null)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
|
{(params.row.declined ? (
|
||||||
|
<Chip icon={<AssignmentLateOutlined />} label="Declined" variant="filled" color="error" />
|
||||||
|
):null)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
|
{(params.row.accepted ? (
|
||||||
|
<Chip icon={<AssignmentTurnedInOutlined />} label="Accepted" variant="filled" color="info" />
|
||||||
|
):null)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
|
{(params.row.paid && params.row.acccepted ? (
|
||||||
|
<Chip label="Paid" variant="filled" color="success" />
|
||||||
|
):null)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
|
{(params.row.paid==false && params.row.accepted ? (
|
||||||
|
<Chip icon={<PriceCheckOutlined />} label="Pending Payment" variant="filled" color="warning" />
|
||||||
|
):null)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
|
{(params.row.completed ? (
|
||||||
|
<Chip disabled={!params.row.completed} icon={<Check />} label="Completed" variant="filled" color="success" />
|
||||||
|
):null)}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={6} sx={{textAlign:"center"}}>
|
||||||
|
<Tooltip arrow title="Rate this request.">
|
||||||
|
<Rating
|
||||||
|
sx={{paddingTop:"1%"}}
|
||||||
|
size='large'
|
||||||
|
// name="simple-controlled"
|
||||||
|
// value={value}
|
||||||
|
// onChange={(event, newValue) => {
|
||||||
|
// setValue(newValue);
|
||||||
|
// }}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip arrow title="Write a review for this request..">
|
||||||
|
<TextField size="small" rows={4} multiline />
|
||||||
|
</Tooltip>
|
||||||
|
</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>
|
||||||
|
);
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ImageList, Box, Button, CircularProgress, Slider } from '@mui/material';
|
import { ImageList, Box, Button, CircularProgress, Slider, IconButton } from '@mui/material';
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import EditableArtistPortfolioImage from './editableArtistPortfolioImage';
|
import EditableArtistPortfolioImage from './editableArtistPortfolioImage';
|
||||||
import FileOpenIcon from '@mui/icons-material/FileOpen';
|
import FileOpenIcon from '@mui/icons-material/FileOpen';
|
||||||
|
import { Tooltip } from '@mui/material';
|
||||||
import { Grid } from '@mui/material';
|
import { Grid } from '@mui/material';
|
||||||
|
import { FileUpload } from '@mui/icons-material';
|
||||||
const EditableArtistPortfolio = ({ artistId }) => {
|
const EditableArtistPortfolio = ({ artistId }) => {
|
||||||
const [portfolioData, setPortfolioData] = useState([]);
|
const [portfolioData, setPortfolioData] = useState([]);
|
||||||
const [columns, setColumns] = useState(2);
|
const [columns, setColumns] = useState(2);
|
||||||
@ -51,7 +53,7 @@ const EditableArtistPortfolio = ({ artistId }) => {
|
|||||||
(
|
(
|
||||||
|
|
||||||
<Grid container spacing={2} sm={12}>
|
<Grid container spacing={2} sm={12}>
|
||||||
<Grid item xs={12} sm={12} sx={{ textAlign: "center" }}>
|
<Grid item xs={12} sm={1} sx={{ textAlign: "center" }}>
|
||||||
<input
|
<input
|
||||||
id="portfolioUploadInput"
|
id="portfolioUploadInput"
|
||||||
style={{ display: 'none' }}
|
style={{ display: 'none' }}
|
||||||
@ -60,19 +62,15 @@ const EditableArtistPortfolio = ({ artistId }) => {
|
|||||||
onChange={handlePortfolioUploadImageChange}
|
onChange={handlePortfolioUploadImageChange}
|
||||||
/>
|
/>
|
||||||
<label htmlFor="portfolioUploadInput">
|
<label htmlFor="portfolioUploadInput">
|
||||||
<Button
|
<Tooltip arrow title="Upload Image To Portfolio">
|
||||||
fullWidth
|
<IconButton color="primary" component="span">
|
||||||
variant='outlined'
|
<FileUpload />
|
||||||
component="span"
|
</IconButton>
|
||||||
size="large"
|
</Tooltip>
|
||||||
sx={{width:"100%"}}
|
|
||||||
startIcon={<FileOpenIcon />}
|
|
||||||
>
|
|
||||||
{(portfolioData.length > 0 ? "Upload Another Portfolio Image" : "Upload Your First Portfolio Image")}
|
|
||||||
</Button>
|
|
||||||
</label>
|
</label>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={12} sx={{ textAlign: "center" }}>
|
<Grid item xs={12} sm={11} sx={{ textAlign: "center" }}>
|
||||||
|
<Tooltip arrow title="Amount of columns">
|
||||||
<Slider
|
<Slider
|
||||||
defaultValue={columns}
|
defaultValue={columns}
|
||||||
aria-labelledby="discrete-slider"
|
aria-labelledby="discrete-slider"
|
||||||
@ -82,6 +80,8 @@ const EditableArtistPortfolio = ({ artistId }) => {
|
|||||||
marks
|
marks
|
||||||
min={1}
|
min={1}
|
||||||
max={5}/>
|
max={5}/>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={12} sx={{maxHeight:"45rem",overflowY:"scroll"}}>
|
<Grid item xs={12} sm={12} sx={{maxHeight:"45rem",overflowY:"scroll"}}>
|
||||||
<ImageList variant='masonry' cols={columns} sx={{ width:"100%" }}>
|
<ImageList variant='masonry' cols={columns} sx={{ width:"100%" }}>
|
@ -1,61 +0,0 @@
|
|||||||
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>
|
|
||||||
);
|
|
||||||
}
|
|
28
components/requestReferences.tsx
Normal file
28
components/requestReferences.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import {useEffect } from "react";
|
||||||
|
import { ImageList, ImageListItem } from '@mui/material';
|
||||||
|
|
||||||
|
export default function RequestReferences({id}) {
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
const [refrences, setReferences] = React.useState([]);
|
||||||
|
|
||||||
|
const getData = async () => {
|
||||||
|
const response = await fetch('/api/requests/' + id + '/references');
|
||||||
|
const references = await response.json();
|
||||||
|
setReferences(references);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (<ImageList>
|
||||||
|
{refrences.map((item) => (
|
||||||
|
<ImageListItem>
|
||||||
|
<img src={item.url} alt={item.title} />
|
||||||
|
</ImageListItem>
|
||||||
|
))}
|
||||||
|
</ImageList>
|
||||||
|
);
|
||||||
|
}
|
85
components/reviews.tsx
Normal file
85
components/reviews.tsx
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { DataGrid } from '@mui/x-data-grid';
|
||||||
|
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
||||||
|
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { Rating } from '@mui/material';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
|
||||||
|
import { DateField } from '@mui/x-date-pickers';
|
||||||
|
|
||||||
|
export default function Reviews({artistId}) {
|
||||||
|
const router = useRouter();
|
||||||
|
const columns = [
|
||||||
|
{ field: 'requestId', headerName: 'Request ID', flex: 0.1},
|
||||||
|
{ field: 'message', headerName: 'Review Message', flex: 0.5},
|
||||||
|
{ field: 'rating', headerName: 'Rating', flex: 0.2, renderCell: (params) => {
|
||||||
|
return <Rating value={params.row.rating} readOnly />;
|
||||||
|
}}
|
||||||
|
];
|
||||||
|
const [isLoading, setIsLoading] = React.useState(true);
|
||||||
|
const [reviewCount, setReviewCount] = React.useState(null);
|
||||||
|
const [reviewData, setReviewData] = React.useState({});
|
||||||
|
const [paginationModel, setPaginationModel] = React.useState({
|
||||||
|
page: 0,
|
||||||
|
pageSize: 15,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const getReviews = async () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
const response = await fetch('/api/discovery/artist/'+artistId+'/reviews', {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
setReviewData(data);
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
const getReviewsCount = async () => {
|
||||||
|
const response = await fetch('/api/discovery/artist/'+artistId+'/reviewscount', {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
setReviewCount(data);
|
||||||
|
setRowCountState((prevRowCountState) =>
|
||||||
|
data !== undefined
|
||||||
|
? data
|
||||||
|
: prevRowCountState,
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some API clients return undefined while loading
|
||||||
|
// Following lines are here to prevent `rowCountState` from being undefined during the loading
|
||||||
|
const [rowCountState, setRowCountState] = React.useState(0);
|
||||||
|
React.useEffect(() => {
|
||||||
|
getReviews();
|
||||||
|
getReviewsCount();
|
||||||
|
}, [reviewCount, setRowCountState,paginationModel]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
|
||||||
|
<div style={{ height: '100%', width: '100%' }}>
|
||||||
|
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||||
|
<DataGrid
|
||||||
|
getRowId={(row) => row.requestId}
|
||||||
|
rows={reviewData}
|
||||||
|
columns={columns}
|
||||||
|
rowCount={rowCountState}
|
||||||
|
loading={isLoading}
|
||||||
|
pageSizeOptions={[15]}
|
||||||
|
paginationModel={paginationModel}
|
||||||
|
paginationMode="server"
|
||||||
|
onPaginationModelChange={setPaginationModel}
|
||||||
|
/>
|
||||||
|
</LocalizationProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -18,7 +18,7 @@ type ThemeConfig = {
|
|||||||
const themeConfig: ThemeConfig = {
|
const themeConfig: ThemeConfig = {
|
||||||
// ** Layout Configs
|
// ** Layout Configs
|
||||||
templateName: 'Request.Box' /* App Name */,
|
templateName: 'Request.Box' /* App Name */,
|
||||||
mode: 'light' /* light | dark */,
|
mode: 'dark' /* light | dark */,
|
||||||
contentWidth: 'boxed' /* full | boxed */,
|
contentWidth: 'boxed' /* full | boxed */,
|
||||||
|
|
||||||
// ** Routing Configs
|
// ** Routing Configs
|
||||||
|
@ -7,7 +7,7 @@ import MuiAppBar, { AppBarProps } from '@mui/material/AppBar'
|
|||||||
import MuiToolbar, { ToolbarProps } from '@mui/material/Toolbar'
|
import MuiToolbar, { ToolbarProps } from '@mui/material/Toolbar'
|
||||||
|
|
||||||
// ** Type Import
|
// ** Type Import
|
||||||
import { Settings } from '../core/context/settingsContext'
|
import { Settings } from '../../../../context/settingsContext'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
hidden: boolean
|
hidden: boolean
|
||||||
|
@ -65,7 +65,7 @@ const AppBarContent = (props: Props) => {
|
|||||||
<Box className='actions-right' sx={{ display: 'flex', alignItems: 'center' }}>
|
<Box className='actions-right' sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
{(profileData ? (
|
{(profileData ? (
|
||||||
<NovuProvider subscriberId={profileData["id"]} applicationIdentifier={'9SKjzgN_odAF'}>
|
<NovuProvider subscriberId={profileData["id"]} applicationIdentifier={'9SKjzgN_odAF'}>
|
||||||
<PopoverNotificationCenter colorScheme={'light'}>
|
<PopoverNotificationCenter colorScheme={'dark'}>
|
||||||
{({ unseenCount }) => <NotificationBell unseenCount={unseenCount} />}
|
{({ unseenCount }) => <NotificationBell unseenCount={unseenCount} />}
|
||||||
</PopoverNotificationCenter>
|
</PopoverNotificationCenter>
|
||||||
</NovuProvider>
|
</NovuProvider>
|
||||||
|
@ -7,8 +7,8 @@ import SettingsApplicationsIcon from '@mui/icons-material/SettingsApplications';
|
|||||||
|
|
||||||
// ** Type import
|
// ** Type import
|
||||||
import { VerticalNavItemsType } from '../../core/layouts/types'
|
import { VerticalNavItemsType } from '../../core/layouts/types'
|
||||||
import { BankTransfer, Cart, Clipboard, PageFirst } from 'mdi-material-ui'
|
import { BankTransfer, Cart, Clipboard, PageFirst, StarOutline } from 'mdi-material-ui'
|
||||||
import { DocumentScanner, FileOpen, Settings } from '@mui/icons-material'
|
import { DocumentScanner, FileOpen, OpenInBrowser, Settings, WebAsset } from '@mui/icons-material'
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
const navigation = (): VerticalNavItemsType => {
|
const navigation = (): VerticalNavItemsType => {
|
||||||
@ -70,6 +70,11 @@ const navigation = (): VerticalNavItemsType => {
|
|||||||
{
|
{
|
||||||
sectionTitle: 'Artist'
|
sectionTitle: 'Artist'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Request Reviews',
|
||||||
|
icon: StarOutline,
|
||||||
|
path: '/dashboard/artist/reviews'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Incoming Requests',
|
title: 'Incoming Requests',
|
||||||
icon: CubeOutline,
|
icon: CubeOutline,
|
||||||
@ -78,21 +83,21 @@ const navigation = (): VerticalNavItemsType => {
|
|||||||
{
|
{
|
||||||
title: 'Payments/Payouts',
|
title: 'Payments/Payouts',
|
||||||
icon: BankTransfer,
|
icon: BankTransfer,
|
||||||
path: '/dashboard/payout'
|
path: '/dashboard/artist/payout'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Shop Settings',
|
title: 'Artist Settings',
|
||||||
icon: SettingsApplicationsIcon,
|
icon: Settings,
|
||||||
path: '/dashboard/artist/artistsettings'
|
path: '/dashboard/artist/artistsettings'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Page Settings',
|
title: 'Page Settings',
|
||||||
icon: DocumentScanner,
|
icon: WebAsset,
|
||||||
path: '/dashboard/artist/pagesettings'
|
path: '/dashboard/artist/pagesettings'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Your Page',
|
title: 'Your Page',
|
||||||
icon: FileOpen,
|
icon: OpenInBrowser,
|
||||||
path: '/box/' + (userData ? userData["displayName"] : "")
|
path: '/box/' + (userData ? userData["displayName"] : "")
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
19
pages/api/artist/reviews.tsx
Normal file
19
pages/api/artist/reviews.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||||
|
|
||||||
|
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||||
|
const { accessToken } = await getAccessToken(req, res);
|
||||||
|
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
|
||||||
|
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Artist/Reviews`;
|
||||||
|
const response = await fetch(apiUrl, {
|
||||||
|
headers: {
|
||||||
|
"Authorization": `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(response.ok==false){
|
||||||
|
res.status(200).json({})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let result = await response.json();
|
||||||
|
res.status(200).json(result);
|
||||||
|
});
|
||||||
|
|
19
pages/api/artist/reviewscount.tsx
Normal file
19
pages/api/artist/reviewscount.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||||
|
|
||||||
|
export default withApiAuthRequired(async function onboardUrl(req, res) {
|
||||||
|
const { accessToken } = await getAccessToken(req, res);
|
||||||
|
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
|
||||||
|
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Artist/Reviews/Count`;
|
||||||
|
const response = await fetch(apiUrl, {
|
||||||
|
headers: {
|
||||||
|
"Authorization": `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(response.ok==false){
|
||||||
|
res.status(200).json({})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let result = await response.json();
|
||||||
|
res.status(200).json(result);
|
||||||
|
});
|
||||||
|
|
13
pages/api/discovery/artist/[sellerId]/reviews.tsx
Normal file
13
pages/api/discovery/artist/[sellerId]/reviews.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export default async function handler(req, res ): Promise<any> {
|
||||||
|
const { sellerId } = req.query;
|
||||||
|
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}/Reviews`;
|
||||||
|
(url)
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to fetch seller portfolio');
|
||||||
|
}
|
||||||
|
var result = await response.json();
|
||||||
|
(result)
|
||||||
|
res.status(200).json(result);
|
||||||
|
}
|
||||||
|
|
13
pages/api/discovery/artist/[sellerId]/reviewscount.tsx
Normal file
13
pages/api/discovery/artist/[sellerId]/reviewscount.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export default async function handler(req, res ): Promise<any> {
|
||||||
|
const { sellerId } = req.query;
|
||||||
|
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}/Reviews/Count`;
|
||||||
|
(url)
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to fetch seller portfolio');
|
||||||
|
}
|
||||||
|
var result = await response.json();
|
||||||
|
(result)
|
||||||
|
res.status(200).json(result);
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,19 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a
|
|||||||
export default withApiAuthRequired(async function products(req, res) {
|
export default withApiAuthRequired(async function products(req, res) {
|
||||||
const { accessToken } = await getAccessToken(req, res);
|
const { accessToken } = await getAccessToken(req, res);
|
||||||
const requestId = req.query.requestId;
|
const requestId = req.query.requestId;
|
||||||
|
if(req.method == 'GET'){
|
||||||
|
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
|
||||||
|
});
|
||||||
|
console.log(response)
|
||||||
|
let result = await response.json();
|
||||||
|
res.status(200).json(result);
|
||||||
|
}
|
||||||
|
else{
|
||||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Reference', {
|
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Reference', {
|
||||||
headers: {
|
headers: {
|
||||||
"Authorization": `Bearer ${accessToken}`,
|
"Authorization": `Bearer ${accessToken}`,
|
||||||
@ -11,7 +24,9 @@ export default withApiAuthRequired(async function products(req, res) {
|
|||||||
method: req.method,
|
method: req.method,
|
||||||
body: req.body
|
body: req.body
|
||||||
});
|
});
|
||||||
|
console.log(response)
|
||||||
let result = await response.json();
|
let result = await response.json();
|
||||||
res.status(200).json(result);
|
res.status(200).json(result);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
17
pages/api/requests/[requestId]/review.tsx
Normal file
17
pages/api/requests/[requestId]/review.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||||
|
|
||||||
|
export default withApiAuthRequired(async function 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+'/Review', {
|
||||||
|
headers: {
|
||||||
|
"Authorization": `Bearer ${accessToken}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(req.body)
|
||||||
|
});
|
||||||
|
let result = await response.json();
|
||||||
|
res.status(200).json(result);
|
||||||
|
});
|
||||||
|
|
@ -1,8 +1,8 @@
|
|||||||
import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
||||||
import { CircularProgress, Grid, Typography } from "@mui/material";
|
import { CircularProgress, Grid, IconButton, Tooltip, Typography } from "@mui/material";
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import CardContent from "@mui/material/CardContent";
|
import CardContent from "@mui/material/CardContent";
|
||||||
import EditableArtistPortfolio from "../../../components/Old/editableArtistPortfolio";
|
import EditableArtistPortfolio from "../../../components/editableArtistPortfolio";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import TextField from '@mui/material/TextField';
|
import TextField from '@mui/material/TextField';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
@ -10,6 +10,7 @@ import Switch from '@mui/material/Switch';
|
|||||||
import Divider from '@mui/material/Divider';
|
import Divider from '@mui/material/Divider';
|
||||||
import ArtistRequest from "../../../components/ArtistRequest";
|
import ArtistRequest from "../../../components/ArtistRequest";
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
|
import { Save } from "@mui/icons-material";
|
||||||
|
|
||||||
const ArtistSettings = () => {
|
const ArtistSettings = () => {
|
||||||
const {user, isLoading} = useUser();
|
const {user, isLoading} = useUser();
|
||||||
@ -91,8 +92,10 @@ const saveChanges = async () => {
|
|||||||
<Grid item xs={12} md={8}>
|
<Grid item xs={12} md={8}>
|
||||||
<Typography variant="h5" gutterBottom>General Settings</Typography>
|
<Typography variant="h5" gutterBottom>General Settings</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={4} >
|
<Grid item xs={12} md={4} sx={{textAlign:"right"}} >
|
||||||
<Button variant="contained" onClick={saveChanges} color="success" fullWidth>{saved ? "Saved" : "Save Changes"}</Button>
|
<Tooltip arrow title="Save Changes">
|
||||||
|
<IconButton onClick={saveChanges} color="success"><Save /></IconButton>
|
||||||
|
</Tooltip>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={12} >
|
<Grid item xs={12} md={12} >
|
||||||
<Grid container spacing={4} sx={{paddingTop:"2%"}}>
|
<Grid container spacing={4} sx={{paddingTop:"2%"}}>
|
||||||
|
@ -7,12 +7,13 @@ import CardMedia from '@mui/material/CardMedia';
|
|||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import EditableArtistPortfolio from "../../../components/Old/editableArtistPortfolio";
|
import EditableArtistPortfolio from "../../../components/editableArtistPortfolio";
|
||||||
import ArtistPortfolio from "../../../components/Old/artistPortfolio";
|
import ArtistPortfolio from "../../../components/artistPortfolio";
|
||||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid';
|
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid';
|
||||||
import Rating from '@mui/material/Rating';
|
import Rating from '@mui/material/Rating';
|
||||||
import CircularProgress from '@mui/material/CircularProgress';
|
import CircularProgress from '@mui/material/CircularProgress';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
|
import Reviews from "../../../components/reviews";
|
||||||
|
|
||||||
const Profile = () => {
|
const Profile = () => {
|
||||||
|
|
||||||
@ -132,19 +133,9 @@ const Profile = () => {
|
|||||||
<Typography variant="h5" align="center" gutterBottom>REVIEWS HEADER</Typography>
|
<Typography variant="h5" align="center" gutterBottom>REVIEWS HEADER</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={12} >
|
<Grid item xs={12} md={12} >
|
||||||
<DataGrid
|
{profileData!=null ? (
|
||||||
rows={rows}
|
<Reviews artistId={profileData["id"]}/>
|
||||||
columns={columns}
|
):null}
|
||||||
autoHeight={true}
|
|
||||||
initialState={{
|
|
||||||
pagination: {
|
|
||||||
paginationModel: {
|
|
||||||
pageSize: 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
pageSizeOptions={[5]}
|
|
||||||
/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
||||||
import { CardHeader, Grid, Typography } from "@mui/material";
|
import { CardHeader, Grid, IconButton, Typography } from "@mui/material";
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import CardContent from "@mui/material/CardContent";
|
import CardContent from "@mui/material/CardContent";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
@ -7,6 +7,7 @@ import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
|
|||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import { OpenInNew } from "@mui/icons-material";
|
import { OpenInNew } from "@mui/icons-material";
|
||||||
import CircularProgress from '@mui/material/CircularProgress';
|
import CircularProgress from '@mui/material/CircularProgress';
|
||||||
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
|
|
||||||
const Payout = () => {
|
const Payout = () => {
|
||||||
@ -33,23 +34,16 @@ const Payout = () => {
|
|||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={12} md={4}>
|
<Grid item xs={12} md={4}>
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader title="Payout Settings" />
|
<CardHeader title="Payout Settings" action ={<Tooltip title="Open Stripe dashboard"><IconButton href={payoutData ? payoutData["payoutUrl"] : ""} target="_blank" color="info"><OpenInNew/></IconButton></Tooltip>}/>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={12} md={4}>
|
<Grid item xs={12} md={6}>
|
||||||
<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"] : ""} />
|
<CurrencyTextField fullWidth label="Current Balance" size="large" disabled variant="standard" currencySymbol="$" outputFormat="string" decimalCharacter="." digitGroupSeparator="," value={payoutData ? payoutData["balance"] : ""} />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={6}>
|
||||||
<CurrencyTextField fullWidth label="Pending Balance" size="large" disabled variant="standard" currencySymbol="$" outputFormat="string" decimalCharacter="." digitGroupSeparator="," value={payoutData ? payoutData["pendingBalance"] : ""} />
|
<CurrencyTextField fullWidth label="Pending Balance" size="large" disabled variant="standard" currencySymbol="$" outputFormat="string" decimalCharacter="." digitGroupSeparator="," value={payoutData ? payoutData["pendingBalance"] : ""} />
|
||||||
</Grid>
|
</Grid>
|
||||||
</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>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</Grid>
|
</Grid>
|
@ -21,9 +21,7 @@ import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn';
|
|||||||
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
|
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
|
||||||
import { Card, CardHeader } from '@mui/material';
|
import { Card, CardHeader } from '@mui/material';
|
||||||
import { Dialog, DialogActions, DialogContent, DialogTitle, Grid, Stack } from '@mui/material';
|
import { Dialog, DialogActions, DialogContent, DialogTitle, Grid, Stack } from '@mui/material';
|
||||||
import RequestReferenceImage from '../../../components/Old/requestReferencesImage';
|
import RequestReferences from '../../../components/requestReferences';
|
||||||
import RequestReferences from '../../../components/Old/requestReferences';
|
|
||||||
|
|
||||||
|
|
||||||
export default function ServerPaginationGrid() {
|
export default function ServerPaginationGrid() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -149,8 +147,10 @@ export default function ServerPaginationGrid() {
|
|||||||
<CardContent>
|
<CardContent>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={12}>
|
||||||
|
<Typography variant="h6" align="center">Reference Images</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={12}>
|
||||||
|
<RequestReferences id={params.row.id} />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@ -161,16 +161,16 @@ export default function ServerPaginationGrid() {
|
|||||||
<Grid item xs={12} md={6}>
|
<Grid item xs={12} md={6}>
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={12}>
|
||||||
<Tooltip title="Decline this request.">
|
<Tooltip arrow title="Decline this request.">
|
||||||
<IconButton onClick={denyRequest} disabled={params.row.declined || params.row.accepted} color="error"><Close/></IconButton>
|
<IconButton onClick={denyRequest} disabled={params.row.declined || params.row.accepted} color="error"><Close/></IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Accept this request.">
|
<Tooltip arrow title="Accept this request.">
|
||||||
<IconButton onClick={acceptRequest} disabled={params.row.declined || params.row.accepted} color="success"><Check/></IconButton>
|
<IconButton onClick={acceptRequest} disabled={params.row.declined || params.row.accepted} color="success"><Check/></IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Upload asset image for customer.">
|
<Tooltip arrow title="Upload asset image for customer.">
|
||||||
<IconButton disabled={!params.row.paid} color="primary"><Upload/></IconButton>
|
<IconButton disabled={!params.row.paid} color="primary"><Upload/></IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Complete this request.">
|
<Tooltip arrow title="Complete this request.">
|
||||||
<IconButton disabled={!params.row.paid || params.row.completed} color="success"><AssignmentTurnedInIcon/></IconButton>
|
<IconButton disabled={!params.row.paid || params.row.completed} color="success"><AssignmentTurnedInIcon/></IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{(!params.row.declined && !params.row.accepted && !params.row.paid && !params.row.completed ? (
|
{(!params.row.declined && !params.row.accepted && !params.row.paid && !params.row.completed ? (
|
||||||
@ -189,7 +189,7 @@ export default function ServerPaginationGrid() {
|
|||||||
<Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="filled" color="warning" />
|
<Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="filled" color="warning" />
|
||||||
):null)}
|
):null)}
|
||||||
{(params.row.completed ? (
|
{(params.row.completed ? (
|
||||||
<Chip disabled={!params.row.completed} icon={<Check />} label="Completed" variant="outlined" color="success" />
|
<Chip disabled={!params.row.completed} icon={<Check />} label="Completed" variant="filled" color="success" />
|
||||||
):null)}
|
):null)}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={12}>
|
||||||
@ -212,13 +212,13 @@ export default function ServerPaginationGrid() {
|
|||||||
<Button onClick={handleClose}>Close</Button>
|
<Button onClick={handleClose}>Close</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<Tooltip title="View more details."><IconButton onClick={viewRequest} aria-label="accept" color="primary" onClick={handleClickOpen}><OpenInNew/></IconButton></Tooltip>
|
<Tooltip arrow 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) ? (
|
{((params.row.accepted==false && params.row.declined==false && params.row.completed==false) ? (
|
||||||
<>
|
<>
|
||||||
<Tooltip title="Accept this request.">
|
<Tooltip arrow title="Accept this request.">
|
||||||
<IconButton onClick={acceptRequest} aria-label="accept" color="success"><Check/></IconButton>
|
<IconButton onClick={acceptRequest} aria-label="accept" color="success"><Check/></IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Deny this request.">
|
<Tooltip arrow title="Deny this request.">
|
||||||
<IconButton onClick={denyRequest} aria-label="deny" sx={{marginLeft:"2px"}} color="error"><Close/></IconButton>
|
<IconButton onClick={denyRequest} aria-label="deny" sx={{marginLeft:"2px"}} color="error"><Close/></IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</>
|
</>
|
||||||
@ -226,7 +226,7 @@ export default function ServerPaginationGrid() {
|
|||||||
)}
|
)}
|
||||||
{((params.row.accepted==true && params.row.declined==false && params.row.completed==false && params.row.paid==true) ? (
|
{((params.row.accepted==true && params.row.declined==false && params.row.completed==false && params.row.paid==true) ? (
|
||||||
<>
|
<>
|
||||||
<Tooltip title="Complete this request.">
|
<Tooltip arrow title="Complete this request.">
|
||||||
<IconButton onClick={completeRequest} aria-label="complete" color="success"><ClipboardCheck/></IconButton>
|
<IconButton onClick={completeRequest} aria-label="complete" color="success"><ClipboardCheck/></IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</>
|
</>
|
||||||
@ -241,7 +241,7 @@ export default function ServerPaginationGrid() {
|
|||||||
const [requestData, setRequestData] = React.useState({});
|
const [requestData, setRequestData] = React.useState({});
|
||||||
const [paginationModel, setPaginationModel] = React.useState({
|
const [paginationModel, setPaginationModel] = React.useState({
|
||||||
page: 0,
|
page: 0,
|
||||||
pageSize: 5,
|
pageSize: 15,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -311,7 +311,7 @@ export default function ServerPaginationGrid() {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
rowCount={rowCountState}
|
rowCount={rowCountState}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
pageSizeOptions={[5]}
|
pageSizeOptions={[15]}
|
||||||
paginationModel={paginationModel}
|
paginationModel={paginationModel}
|
||||||
paginationMode="server"
|
paginationMode="server"
|
||||||
onPaginationModelChange={handlePageChange}
|
onPaginationModelChange={handlePageChange}
|
||||||
|
97
pages/dashboard/artist/reviews.tsx
Normal file
97
pages/dashboard/artist/reviews.tsx
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { DataGrid } from '@mui/x-data-grid';
|
||||||
|
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
||||||
|
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { Rating } from '@mui/material';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
|
||||||
|
import { DateField } from '@mui/x-date-pickers';
|
||||||
|
|
||||||
|
export default function ServerPaginationGrid() {
|
||||||
|
const router = useRouter();
|
||||||
|
const columns = [
|
||||||
|
{ field: 'requestId', headerName: 'Request ID', flex: 0.1},
|
||||||
|
{ field: 'message', headerName: 'Review Message', flex: 0.5},
|
||||||
|
{ field: 'rating', headerName: 'Rating', flex: 0.2, renderCell: (params) => {
|
||||||
|
return <Rating value={params.row.rating} readOnly />;
|
||||||
|
}},
|
||||||
|
{ field: 'reviewDate', headerName: 'Reviewed On', flex: 0.2, renderCell: (params) => {
|
||||||
|
let formattedTime = ""
|
||||||
|
const date = new Date(params.row.reviewDate);
|
||||||
|
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.reviewDate)}
|
||||||
|
format="LL"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const [isLoading, setIsLoading] = React.useState(true);
|
||||||
|
const [reviewCount, setReviewCount] = React.useState(null);
|
||||||
|
const [reviewData, setReviewData] = React.useState({});
|
||||||
|
const [paginationModel, setPaginationModel] = React.useState({
|
||||||
|
page: 0,
|
||||||
|
pageSize: 15,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const getReviews = async () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
const response = await fetch('/api/artist/reviews', {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
setReviewData(data);
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
const getReviewsCount = async () => {
|
||||||
|
const response = await fetch('/api/artist/reviewscount', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
setReviewCount(data);
|
||||||
|
setRowCountState((prevRowCountState) =>
|
||||||
|
data !== undefined
|
||||||
|
? data
|
||||||
|
: prevRowCountState,
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some API clients return undefined while loading
|
||||||
|
// Following lines are here to prevent `rowCountState` from being undefined during the loading
|
||||||
|
const [rowCountState, setRowCountState] = React.useState(0);
|
||||||
|
React.useEffect(() => {
|
||||||
|
getReviews();
|
||||||
|
getReviewsCount();
|
||||||
|
}, [reviewCount, setRowCountState,paginationModel]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
|
||||||
|
<div style={{ height: '100%', width: '100%' }}>
|
||||||
|
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||||
|
<DataGrid
|
||||||
|
getRowId={(row) => row.requestId}
|
||||||
|
rows={reviewData}
|
||||||
|
columns={columns}
|
||||||
|
rowCount={rowCountState}
|
||||||
|
loading={isLoading}
|
||||||
|
pageSizeOptions={[15]}
|
||||||
|
paginationModel={paginationModel}
|
||||||
|
paginationMode="server"
|
||||||
|
onPaginationModelChange={setPaginationModel}
|
||||||
|
/>
|
||||||
|
</LocalizationProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -13,7 +13,7 @@ import CardStatisticsVerticalComponent from '../../core/components/card-statisti
|
|||||||
|
|
||||||
// ** Styled Component Import
|
// ** Styled Component Import
|
||||||
import ApexChartWrapper from '../../core/styles/libs/react-apexcharts'
|
import ApexChartWrapper from '../../core/styles/libs/react-apexcharts'
|
||||||
import { Card, TextField, Typography } from '@mui/material'
|
import { Card, IconButton, TextField, Typography } from '@mui/material'
|
||||||
import { withApiAuthRequired } from "@auth0/nextjs-auth0";
|
import { withApiAuthRequired } from "@auth0/nextjs-auth0";
|
||||||
import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'
|
import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'
|
||||||
import Button from '@mui/material/Button'
|
import Button from '@mui/material/Button'
|
||||||
@ -26,13 +26,16 @@ import { isObject } from 'util'
|
|||||||
import Orders from '../../components/Orders'
|
import Orders from '../../components/Orders'
|
||||||
import StatisticsCard from '../../views/dashboard/StatisticsCard'
|
import StatisticsCard from '../../views/dashboard/StatisticsCard'
|
||||||
import ArtistStats from '../../components/ArtistStats'
|
import ArtistStats from '../../components/ArtistStats'
|
||||||
import { Clipboard } from 'mdi-material-ui'
|
import { ArrowDownBox, BankTransfer, Cash, Clipboard, CubeOutline, StarOutline } from 'mdi-material-ui'
|
||||||
import CircularProgress from '@mui/material/CircularProgress'
|
import CircularProgress from '@mui/material/CircularProgress'
|
||||||
|
import Tooltip from '@mui/material/Tooltip'
|
||||||
import Box from '@mui/material/Box'
|
import Box from '@mui/material/Box'
|
||||||
|
import { Fullscreen, OpenInBrowser, Settings, WebAsset } from '@mui/icons-material'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
|
const [userData , setUserData] = useState(null)
|
||||||
const [profileData, setArtistData] = useState(null);
|
const [profileData, setArtistData] = useState(null);
|
||||||
const [requestData, setArtistRequestData] = useState(null);
|
const [requestData, setArtistRequestData] = useState(null);
|
||||||
const [onboardData, setOnboardedData] = useState(false);
|
const [onboardData, setOnboardedData] = useState(false);
|
||||||
@ -46,6 +49,9 @@ const Dashboard = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
|
const userResponse = await fetch('/api/me');
|
||||||
|
const user = await userResponse.json();
|
||||||
|
setUserData(user);
|
||||||
const profileResponse = await fetch('/api/artist/profile');
|
const profileResponse = await fetch('/api/artist/profile');
|
||||||
const sellerProfile = await profileResponse.json();
|
const sellerProfile = await profileResponse.json();
|
||||||
setArtistData(sellerProfile);
|
setArtistData(sellerProfile);
|
||||||
@ -96,8 +102,10 @@ const Dashboard = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={4} sx={{textAlign:"center"}}>
|
<Grid item xs={12} md={4} sx={{textAlign:"center"}}>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={5} sx={{textAlign:"center"}}>
|
<Grid item xs={12} md={5} sx={{textAlign:"right"}}>
|
||||||
<Button color="info" onClick={()=>{router.push("/dashboard/requests")}} fullWidth variant="contained">View All Requests</Button>
|
<Tooltip title="Open an expanded view of your requests .">
|
||||||
|
<IconButton color="info" onClick={()=>{router.push("/dashboard/requests")}}><Fullscreen/></IconButton>
|
||||||
|
</Tooltip>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={12} sx={{paddingTop:"2%"}}>
|
<Grid item xs={12} md={12} sx={{paddingTop:"2%"}}>
|
||||||
<Orders />
|
<Orders />
|
||||||
@ -124,27 +132,41 @@ const Dashboard = () => {
|
|||||||
null
|
null
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={8}>
|
<Grid item xs={12} md={12}>
|
||||||
<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>
|
<Tooltip title="Open an expanded view of your reviews.">
|
||||||
|
<IconButton color="info" onClick={() => {router.push("/dashboard/artist/reviews") }} size="large">
|
||||||
|
<StarOutline style={{ fontSize: 64 }} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title="Open an expanded view of your requests.">
|
||||||
|
<IconButton color="info" onClick={() => {router.push("/dashboard/artist/requests") }} size="large">
|
||||||
|
<CubeOutline style={{ fontSize: 64 }} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title="View your payouts and request related transactions.">
|
||||||
|
<IconButton color="success" onClick={() => { router.push("/dashboard/artist/payout") }} size="large">
|
||||||
|
<BankTransfer style={{ fontSize: 64 }} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={2}>
|
<Grid item xs={12} md={12}>
|
||||||
<Button color="info" startIcon={<Clipboard/>} onClick={()=>{router.push("/dashboard/artist/artistsettings#portfolio")}} fullWidth variant="outlined">Copy</Button>
|
<Tooltip title="Manage the settings of your artist account.">
|
||||||
</Grid>
|
<IconButton color="primary" onClick={() => { router.push("/dashboard/artist/artistsettings") }} size="large">
|
||||||
<Grid item xs={12} md={2}>
|
<Settings style={{ fontSize: 64 }} />
|
||||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/artistsettings#portfolio")}} fullWidth variant="outlined">Preview</Button>
|
</IconButton>
|
||||||
</Grid>
|
</Tooltip>
|
||||||
<Grid item xs={12} md={6}>
|
<Tooltip title="Manage the settings of your artist page.">
|
||||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/artistsettings#portfolio")}} fullWidth variant="contained">Manage Portfolio</Button>
|
<IconButton color="primary" onClick={() => { router.push("/dashboard/artist/pagesettings") }} size="large">
|
||||||
</Grid>
|
<WebAsset style={{ fontSize: 64 }} />
|
||||||
<Grid item xs={12} md={6}>
|
</IconButton>
|
||||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/pagesettings")}} fullWidth variant="contained">Design Store Page</Button>
|
</Tooltip>
|
||||||
</Grid>
|
<Tooltip title="Open your artist page.">
|
||||||
<Grid item xs={12} md={6}>
|
<IconButton color="primary" onClick={() => { router.push("/box/"+userData["displayName"]) }} size="large">
|
||||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/pagesettings")}} fullWidth variant="contained">Payment Portal</Button>
|
<OpenInBrowser style={{ fontSize: 64 }} />
|
||||||
</Grid>
|
</IconButton>
|
||||||
<Grid item xs={12} md={6}>
|
</Tooltip>
|
||||||
<Button color="secondary" onClick={()=>{router.push("/dashboard/artist/artistsettings")}} fullWidth variant="contained">Configure Your Shop</Button>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -8,7 +8,7 @@ import { DateField } from '@mui/x-date-pickers/DateField';
|
|||||||
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
||||||
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
||||||
import Chip from '@mui/material/Chip';
|
import Chip from '@mui/material/Chip';
|
||||||
import {Check, Close, Download, OpenInFull, OpenInNew, Refresh, Upload } from '@mui/icons-material';
|
import {Check, Close, Download, OpenInFull, OpenInNew, Refresh, Star, Upload } from '@mui/icons-material';
|
||||||
import PriceCheckIcon from '@mui/icons-material/PriceCheck';
|
import PriceCheckIcon from '@mui/icons-material/PriceCheck';
|
||||||
import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn';
|
import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn';
|
||||||
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
|
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
|
||||||
@ -16,12 +16,12 @@ import ShoppingCartCheckoutIcon from '@mui/icons-material/ShoppingCartCheckout';
|
|||||||
import { IconButton } from '@mui/material';
|
import { IconButton } from '@mui/material';
|
||||||
import Tooltip from '@mui/material/Tooltip';
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
import { Card, CardContent } from '@mui/material';
|
import { Card, CardContent } from '@mui/material';
|
||||||
|
import Rating from '@mui/material/Rating';
|
||||||
|
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { DownloadBox } from 'mdi-material-ui';
|
import { DownloadBox, StarOutline } from 'mdi-material-ui';
|
||||||
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material';
|
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material';
|
||||||
import RequestDialog from '../../components/requestDialog';
|
|
||||||
import { Grid } from '@mui/material';
|
import { Grid } from '@mui/material';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
@ -115,7 +115,9 @@ export default function ServerPaginationGrid() {
|
|||||||
window.open(paymentUrl);
|
window.open(paymentUrl);
|
||||||
}
|
}
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
|
const [rating, setRating] = React.useState(params.row.reviewRating);
|
||||||
|
const [review, setReview] = React.useState(params.row.reviewMessage);
|
||||||
|
const [alreadyReviewed, setAlreadyReviewed] = React.useState(params.row.reviewMessage != null && params.row.reviewMessage != "");
|
||||||
const handleClickOpen = () => {
|
const handleClickOpen = () => {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
};
|
};
|
||||||
@ -124,6 +126,31 @@ export default function ServerPaginationGrid() {
|
|||||||
setOpen(false);
|
setOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const handleReviewChange = (event) => {
|
||||||
|
setReview(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRatingChange = async (event) => {
|
||||||
|
var rating = event.target.value;
|
||||||
|
var response = await fetch('/api/requests/'+params.row.id+'/review', {
|
||||||
|
method:"PUT",
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
rating: rating,
|
||||||
|
message: review
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if(response.ok){
|
||||||
|
router.push("/dashboard/requests")
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
alert("Could not submit review!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let formattedTime = ""
|
let formattedTime = ""
|
||||||
const date = new Date(params.row.requestDate);
|
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
|
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
|
||||||
@ -166,35 +193,74 @@ export default function ServerPaginationGrid() {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={6}>
|
<Grid item xs={12} md={6}>
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={6}>
|
||||||
<Tooltip title="Upload reference image.">
|
<Grid container>
|
||||||
<IconButton disabled={params.row.accepted && params.row.paid} color="primary"><Upload/></IconButton>
|
<Grid item xs={12} md={6}>
|
||||||
</Tooltip>
|
<Grid container>
|
||||||
<Tooltip title="Pay for this request.">
|
<Grid item xs={12} md={3}>
|
||||||
|
<Tooltip arrow title="Pay for this request.">
|
||||||
<IconButton onClick={handlePay} disabled={params.row.accepted && params.row.paid || params.row.declined} color="success"><ShoppingCartCheckoutIcon/></IconButton>
|
<IconButton onClick={handlePay} disabled={params.row.accepted && params.row.paid || params.row.declined} color="success"><ShoppingCartCheckoutIcon/></IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Download all assets.">
|
</Grid>
|
||||||
|
<Grid item xs={12} md={3}>
|
||||||
|
<Tooltip arrow title="Download all assets.">
|
||||||
<IconButton disabled={!params.row.completed} color="secondary"><Download/></IconButton>
|
<IconButton disabled={!params.row.completed} color="secondary"><Download/></IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<Grid container spacing={1}>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
{(!params.row.declined && !params.row.accepted && !params.row.paid && !params.row.completed ? (
|
{(!params.row.declined && !params.row.accepted && !params.row.paid && !params.row.completed ? (
|
||||||
<Chip icon={<Refresh />} label="Pending" variant="filled" color="secondary" />
|
<Chip icon={<Refresh />} label="Pending" variant="filled" color="secondary" />
|
||||||
):null)}
|
):null)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
{(params.row.declined ? (
|
{(params.row.declined ? (
|
||||||
<Chip icon={<AssignmentLateIcon />} label="Declined" variant="filled" color="error" />
|
<Chip icon={<AssignmentLateIcon />} label="Declined" variant="filled" color="error" />
|
||||||
):null)}
|
):null)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
{(params.row.accepted ? (
|
{(params.row.accepted ? (
|
||||||
<Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="filled" color="info" />
|
<Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="filled" color="info" />
|
||||||
):null)}
|
):null)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
{(params.row.paid && params.row.acccepted ? (
|
{(params.row.paid && params.row.acccepted ? (
|
||||||
<Chip label="Paid" variant="filled" color="success" />
|
<Chip label="Paid" variant="filled" color="success" />
|
||||||
):null)}
|
):null)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
{(params.row.paid==false && params.row.accepted ? (
|
{(params.row.paid==false && params.row.accepted ? (
|
||||||
<Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="filled" color="warning" />
|
<Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="filled" color="warning" />
|
||||||
):null)}
|
):null)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
{(params.row.completed ? (
|
{(params.row.completed ? (
|
||||||
<Chip disabled={!params.row.completed} icon={<Check />} label="Completed" variant="outlined" color="success" />
|
<Chip disabled={!params.row.completed} icon={<Check />} label="Completed" variant="filled" color="success" />
|
||||||
):null)}
|
):null)}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
{(params.row.completed) ? (
|
||||||
|
<Grid item xs={12} md={6} sx={{textAlign:"center"}}>
|
||||||
|
<Tooltip arrow title="Rate this request.">
|
||||||
|
<Rating
|
||||||
|
sx={{paddingTop:"1%"}}
|
||||||
|
size='large'
|
||||||
|
value={rating}
|
||||||
|
onChange={handleRatingChange}
|
||||||
|
disabled={alreadyReviewed}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip arrow title={alreadyReviewed ? "The review you left for this request." : "Write a review for this request."}>
|
||||||
|
<TextField disabled={alreadyReviewed} onChange={handleReviewChange} size="small" value={params.row.reviewMessage} focused rows={4} multiline></TextField>
|
||||||
|
</Tooltip>
|
||||||
|
</Grid>
|
||||||
|
):null}
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={12}>
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
@ -215,13 +281,13 @@ export default function ServerPaginationGrid() {
|
|||||||
<Button onClick={handleClose}>Close</Button>
|
<Button onClick={handleClose}>Close</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<Tooltip title="View more details."><IconButton onClick={handleClickOpen} aria-label="accept" color="primary"><OpenInNew/></IconButton></Tooltip>
|
<Tooltip arrow 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) ? (
|
{((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>
|
<Tooltip arrow title="Pay for this request."><IconButton onClick={handlePay} aria-label="accept" color="success"><ShoppingCartCheckoutIcon/></IconButton></Tooltip>
|
||||||
): null
|
): null
|
||||||
)}
|
)}
|
||||||
{((params.row.completed) ? (
|
{((params.row.completed) ? (
|
||||||
<Tooltip title="Download requests assets."><IconButton aria-label="download" color="secondary"><Download/></IconButton></Tooltip>
|
<Tooltip arrow title="Download requests assets."><IconButton aria-label="download" color="secondary"><Download/></IconButton></Tooltip>
|
||||||
): null
|
): null
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
@ -233,7 +299,7 @@ export default function ServerPaginationGrid() {
|
|||||||
const [requestData, setRequestData] = React.useState({});
|
const [requestData, setRequestData] = React.useState({});
|
||||||
const [paginationModel, setPaginationModel] = React.useState({
|
const [paginationModel, setPaginationModel] = React.useState({
|
||||||
page: 0,
|
page: 0,
|
||||||
pageSize: 5,
|
pageSize: 15,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -299,7 +365,7 @@ export default function ServerPaginationGrid() {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
rowCount={rowCountState}
|
rowCount={rowCountState}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
pageSizeOptions={[5]}
|
pageSizeOptions={[15]}
|
||||||
paginationModel={paginationModel}
|
paginationModel={paginationModel}
|
||||||
paginationMode="server"
|
paginationMode="server"
|
||||||
onPaginationModelChange={setPaginationModel}
|
onPaginationModelChange={setPaginationModel}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useUser, withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
import { useUser, withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
||||||
import { CircularProgress, Grid, Typography } from "@mui/material";
|
import { CircularProgress, Grid, IconButton, Typography } from "@mui/material";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import CardContent from "@mui/material/CardContent";
|
import CardContent from "@mui/material/CardContent";
|
||||||
@ -7,6 +7,8 @@ import TextField from '@mui/material/TextField';
|
|||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { Save } from "@mui/icons-material";
|
||||||
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
|
|
||||||
|
|
||||||
const ArtistSettings = () => {
|
const ArtistSettings = () => {
|
||||||
@ -64,11 +66,9 @@ const ArtistSettings = () => {
|
|||||||
<Typography variant="h5" gutterBottom>General Settings</Typography>
|
<Typography variant="h5" gutterBottom>General Settings</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={4} >
|
<Grid item xs={12} md={4} >
|
||||||
{(saved) ? (
|
<Tooltip title="Save changes">
|
||||||
<Button variant="contained" color="success" fullWidth onClick={saveChanges}>Saved</Button>
|
<IconButton onClick={saveChanges} color="success" sx={{float:"right"}}><Save/></IconButton>
|
||||||
):(
|
</Tooltip>
|
||||||
<Button variant="contained" color="success" fullWidth onClick={saveChanges}>Save Changes</Button>
|
|
||||||
)}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md={12} sx={{ paddingTop: "2%" }}>
|
<Grid item xs={12} md={12} sx={{ paddingTop: "2%" }}>
|
||||||
<TextField id="outlined-basic" label="Display Name" onChange={handleDisplayNameChange} variant="outlined" fullWidth value={displayName} />
|
<TextField id="outlined-basic" label="Display Name" onChange={handleDisplayNameChange} variant="outlined" fullWidth value={displayName} />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user