Compare commits

...

10 Commits
0.8.1 ... main

Author SHA1 Message Date
01cc7eb197 Revert "dockerfile"
This reverts commit 2d4663ef7416ea2f3efe808f0cfca9a0557f0dc3.
2024-05-21 22:35:19 -04:00
2d4663ef74 dockerfile 2024-05-21 22:35:13 -04:00
Damien Ostler
0807d6d11d fix: removed logo that is broken 2024-03-17 06:56:35 -04:00
Damien Ostler
2a405067d8 feat: added pages for viewing artist access requests, users, and artists in the admin menus 2024-03-17 06:47:37 -04:00
Damien Ostler
23ea8eed79 fix: admin menus dont show up for non admins now 2024-03-03 16:23:40 -05:00
Damien Ostler
8569290c0e chore: cleaned up the naming of components, apis, and pgaes. 2024-03-03 16:19:47 -05:00
Damien Ostler
5a2f43768d feat: admin list pages and apis 2024-03-03 16:03:22 -05:00
Damien Ostler
ff465278ad fix: filtering and sorting disabled now 2024-03-03 14:11:43 -05:00
Damien Ostler
a63d7f35b8 fix: upload button enabled when not paid 2024-03-02 01:23:02 -05:00
Damien Ostler
93d4518500 feat: refactoring + assets and reference images and reviews 2024-03-02 00:51:43 -05:00
90 changed files with 2899 additions and 2616 deletions

View File

@ -10,8 +10,7 @@ import Typography from '@mui/material/Typography';
import MenuItem from '@mui/material/MenuItem';
import Drawer from '@mui/material/Drawer';
import MenuIcon from '@mui/icons-material/Menu';
import ToggleColorMode from './ToggleColorMode';
import { ArrowLeftOutlined, ArrowRightRounded, Logout, OpenInNew } from '@mui/icons-material';
import { Logout, OpenInNew } from '@mui/icons-material';
const logoStyle = {
width: '140px',

View File

@ -1,143 +0,0 @@
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>
);
}

View File

@ -1,28 +0,0 @@
import * as React from 'react';
import ImageList from '@mui/material/ImageList';
import ImageListItem from '@mui/material/ImageListItem';
import { useEffect, useState } from "react";
import { CircularProgress } from '@mui/material';
import { IconButton } from '@mui/material';
const ArtistPortfolioImage = ({artistId,itemId}) => {
const [loaded, setLoaded] = useState(false);
const handleImageLoaded = () => {
setLoaded(true);
};
return (
<ImageListItem key={itemId } >
<img
srcSet={process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/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' }}
onLoad={handleImageLoaded}
/>
</ImageListItem>)
}
export default ArtistPortfolioImage

View File

@ -1,19 +1,8 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Stepper from '@mui/material/Stepper';
import Step from '@mui/material/Step';
import StepLabel from '@mui/material/StepLabel';
import StepContent from '@mui/material/StepContent';
import Button from '@mui/material/Button';
import Paper from '@mui/material/Paper';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Grid'
import TextField from '@mui/material/TextField';
import ArtistDashboardRequest from './artistDashboardRequest';
import ArtistPortfolio from '../components/artistPortfolio';
import EditableArtistPortfolio from '../components/editableArtistPortfolio';
import {Box,Stepper,Step,StepLabel,StepContent,Button,Paper,Typography,Grid,TextField} from "@mui/material"
import ArtistDashboardRequest from './artistRequest';
import EditableArtistPortfolio from './artist/editablePortfolio';
import { useEffect, useState } from "react";
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
import {Card, CardContent, CardHeader, Divider } from '@mui/material';

View File

@ -9,7 +9,7 @@ import { useEffect, useState } from "react";
export default function ArtistRequest({id,userid,username,message,date,reload}) {
export default function AdminArtistRequest({id,userid,username,message,date,reload}) {
useEffect(() => {

View File

@ -0,0 +1,41 @@
import * as React from 'react';
import ImageListItem from '@mui/material/ImageListItem';
import { useState } from "react";
import Dialog from '@mui/material/Dialog';
import DialogContent from '@mui/material/DialogContent';
const AssetImage = ({ assetId, requestId }) => {
const [loaded, setLoaded] = useState(false);
const [openDialog, setOpenDialog] = useState(false);
const url = "/api/artist/requests/"+requestId+"/assets/"+assetId
const handleImageLoaded = () => {
setLoaded(true);
};
return (
<>
<ImageListItem key={assetId} onClick={() => setOpenDialog(true)}>
<img
srcSet={url}
src={url}
alt={assetId}
loading="lazy"
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
onLoad={handleImageLoaded}
/>
</ImageListItem>
{/* Dialog for displaying full-screen image */}
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
<DialogContent>
<img
src={url}
alt={assetId}
style={{ width: '100%', height: 'auto' }}
/>
</DialogContent>
</Dialog>
</>
);
}
export default AssetImage;

View File

@ -0,0 +1,41 @@
import * as React from 'react';
import ImageListItem from '@mui/material/ImageListItem';
import { useState } from "react";
import Dialog from '@mui/material/Dialog';
import DialogContent from '@mui/material/DialogContent';
const ReferenceImage = ({ referenceId, requestId }) => {
const [loaded, setLoaded] = useState(false);
const [openDialog, setOpenDialog] = useState(false);
const url = "/api/artist/requests/"+requestId+"/references/"+referenceId
const handleImageLoaded = () => {
setLoaded(true);
};
return (
<>
<ImageListItem key={referenceId} onClick={() => setOpenDialog(true)}>
<img
srcSet={url}
src={url}
alt={referenceId}
loading="lazy"
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
onLoad={handleImageLoaded}
/>
</ImageListItem>
{/* Dialog for displaying full-screen image */}
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
<DialogContent>
<img
src={url}
alt={referenceId}
style={{ width: '100%', height: 'auto' }}
/>
</DialogContent>
</Dialog>
</>
);
}
export default ReferenceImage;

View File

@ -1,11 +1,9 @@
import * as React from 'react';
import { ImageList, Box, Button, CircularProgress, Slider, IconButton } from '@mui/material';
import { useEffect, useState } from "react";
import EditableArtistPortfolioImage from './editableArtistPortfolioImage';
import FileOpenIcon from '@mui/icons-material/FileOpen';
import { Tooltip } from '@mui/material';
import { Grid } from '@mui/material';
import { Grid, ImageList, Box, Tooltip, CircularProgress, Slider, IconButton } from '@mui/material';
import { FileUpload } from '@mui/icons-material';
import EditableArtistPortfolioImage from './editablePortfolioImage';
const EditableArtistPortfolio = ({ artistId }) => {
const [portfolioData, setPortfolioData] = useState([]);
const [columns, setColumns] = useState(2);
@ -64,7 +62,7 @@ const EditableArtistPortfolio = ({ artistId }) => {
<label htmlFor="portfolioUploadInput">
<Tooltip arrow title="Upload Image To Portfolio">
<IconButton color="primary" component="span">
<FileUpload />
<FileUpload sx={{fontSize:"2rem"}}/>
</IconButton>
</Tooltip>
</label>

View File

@ -0,0 +1,59 @@
import * as React from 'react';
import DeleteIcon from '@mui/icons-material/Delete';
import { Dialog, DialogContent, ImageList,ImageListItem, ImageListItemBar } from '@mui/material';
import { IconButton } from '@mui/material';
import { useEffect, useState } from "react";
const EditableArtistPortfolioImage = ({ artistId, itemId, reload }) => {
const [loaded, setLoaded] = useState(false);
const [deleting, setDeleting] = useState(false);
const [openDialog, setOpenDialog] = useState(false); // State for controlling the dialog
const handleImageLoaded = () => {
setLoaded(true);
};
const deleteButton = () => {
setDeleting(true);
fetch('/api/artist/portfolio/' + itemId + "/delete", {
method: 'DELETE'
}).then(response => {
reload().then(data => {
})
})
}
return (
<>
<ImageListItem key={itemId} onClick={() => setOpenDialog(true)}>
<img
srcSet={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
alt={itemId}
loading="lazy"
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
onLoad={handleImageLoaded}
/>
<ImageListItemBar
actionIcon={
<IconButton onClick={deleteButton} color="error">
<DeleteIcon />
</IconButton>
}>
</ImageListItemBar>
</ImageListItem>
{/* Dialog for displaying full-screen image */}
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
<DialogContent>
<img
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
alt={itemId}
style={{ width: '100%', height: 'auto' }}
/>
</DialogContent>
</Dialog>
</>
);
}
export default EditableArtistPortfolioImage;

View File

@ -1,8 +1,7 @@
import * as React from 'react';
import {ImageList, Box, Typography, CircularProgress} from '@mui/material';
import { useEffect, useState } from "react";
import ArtistPortfolioImage from './artistPortfolioImage';
import ArtistPortfolioImage from './portfolioImage';
const ArtistPortfolio = ({masonry,columns,artistId}) => {
const [portfolioData, setPortfolioData] = useState([]);
const [profileId, setArtistId] = useState(artistId)

View File

@ -0,0 +1,41 @@
import * as React from 'react';
import ImageListItem from '@mui/material/ImageListItem';
import { useState } from "react";
import Dialog from '@mui/material/Dialog';
import DialogContent from '@mui/material/DialogContent';
const ArtistPortfolioImage = ({ artistId, itemId }) => {
const [loaded, setLoaded] = useState(false);
const [openDialog, setOpenDialog] = useState(false);
const handleImageLoaded = () => {
setLoaded(true);
};
return (
<>
<ImageListItem key={itemId} onClick={() => setOpenDialog(true)}>
<img
srcSet={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
alt={itemId}
loading="lazy"
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
onLoad={handleImageLoaded}
/>
</ImageListItem>
{/* Dialog for displaying full-screen image */}
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
<DialogContent>
<img
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
alt={itemId}
style={{ width: '100%', height: 'auto' }}
/>
</DialogContent>
</Dialog>
</>
);
}
export default ArtistPortfolioImage;

View File

@ -4,16 +4,12 @@ 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: 'requestId', headerName: 'ID', flex: 0.1},
{ field: 'message', headerName: 'Review', flex: 0.5},
{ field: 'rating', headerName: 'Rating', flex: 0.2, renderCell: (params) => {
return <Rating value={params.row.rating} readOnly />;
}}
@ -36,9 +32,13 @@ export default function Reviews({artistId}) {
}
});
const data = await response.json();
setReviewData(data);
// Assuming your API returns an array under a key like 'reviews'
// Adjust this according to your actual API response structure
const rows = data.reviews || []; // If 'reviews' doesn't exist, default to an empty array
setReviewData(rows);
setIsLoading(false);
}
const getReviewsCount = async () => {
const response = await fetch('/api/discovery/artist/'+artistId+'/reviewscount', {
method: 'GET',

View File

@ -5,7 +5,7 @@ import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box';
const ArtistDashboardRequest = () => {
const ArtistOnboardRequest = () => {
const [sellerRequestData, setArtistRequestData] = useState(null);
const getData = async () => {
@ -50,4 +50,4 @@ const ArtistDashboardRequest = () => {
))
)
}
export default ArtistDashboardRequest
export default ArtistOnboardRequest

View File

@ -0,0 +1,41 @@
import * as React from 'react';
import ImageListItem from '@mui/material/ImageListItem';
import { useState } from "react";
import Dialog from '@mui/material/Dialog';
import DialogContent from '@mui/material/DialogContent';
const AssetImage = ({ assetId, requestId }) => {
const [loaded, setLoaded] = useState(false);
const [openDialog, setOpenDialog] = useState(false);
const url = "/api/requests/"+requestId+"/assets/"+assetId
const handleImageLoaded = () => {
setLoaded(true);
};
return (
<>
<ImageListItem key={assetId} onClick={() => setOpenDialog(true)}>
<img
srcSet={url}
src={url}
alt={assetId}
loading="lazy"
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
onLoad={handleImageLoaded}
/>
</ImageListItem>
{/* Dialog for displaying full-screen image */}
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
<DialogContent>
<img
src={url}
alt={assetId}
style={{ width: '100%', height: 'auto' }}
/>
</DialogContent>
</Dialog>
</>
);
}
export default AssetImage;

View File

@ -0,0 +1,41 @@
import * as React from 'react';
import ImageListItem from '@mui/material/ImageListItem';
import { useState } from "react";
import Dialog from '@mui/material/Dialog';
import DialogContent from '@mui/material/DialogContent';
const ReferenceImage = ({ referenceId, requestId }) => {
const [loaded, setLoaded] = useState(false);
const [openDialog, setOpenDialog] = useState(false);
const url = "/api/requests/"+requestId+"/references/"+referenceId
const handleImageLoaded = () => {
setLoaded(true);
};
return (
<>
<ImageListItem key={referenceId} onClick={() => setOpenDialog(true)}>
<img
srcSet={url}
src={url}
alt={referenceId}
loading="lazy"
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
onLoad={handleImageLoaded}
/>
</ImageListItem>
{/* Dialog for displaying full-screen image */}
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
<DialogContent>
<img
src={url}
alt={referenceId}
style={{ width: '100%', height: 'auto' }}
/>
</DialogContent>
</Dialog>
</>
);
}
export default ReferenceImage;

View File

@ -12,11 +12,15 @@ import {Check, Refresh } from '@mui/icons-material';
import PriceCheckIcon from '@mui/icons-material/PriceCheck';
import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn';
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
import { useEffect, useState } from "react";
import { useMediaQuery } from '@mui/material';
import dayjs from 'dayjs';
export default function ServerPaginationGrid() {
export default function CustomerOrders() {
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm')); // Check if the screen size is small
const columns = [
{ field: 'id', headerName: 'ID', flex: 0.1},
{ field: 'status', headerName: 'Status', flex: 0.15,
@ -41,12 +45,15 @@ export default function ServerPaginationGrid() {
}
}
},
{ field: 'amount', headerName: 'Amount', flex: 0.1, renderCell: (params) => {
{ field: 'amount', headerName: '$', flex: 0.1, renderCell: (params) => {
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
}},
{ field: 'requestDate', headerName: 'Request Date', flex:0.15, type: 'date' ,
valueGetter: (params) => { return new Date(params.row.requestDate); }}
];
if(!isSmallScreen){
columns.push(
{ field: 'requestDate', headerName: 'Request Date', flex:0.15, type: 'date' ,
valueGetter: (params) => { return new Date(params.row.requestDate); }} );
}
const [isLoading, setIsLoading] = React.useState(true);
const [requestCount, setRequestCount] = React.useState(null);
const [requestData, setRequestData] = React.useState({});

View File

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

View File

@ -1,28 +0,0 @@
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>
);
}

0
components/test.tsx Normal file
View File

View File

@ -1,325 +0,0 @@
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&apos;re finished</Typography>
<Button onClick={handleReset} sx={{ mt: 1, mr: 1 }}>
Reset
</Button>
</Paper>
)}
</Card>
);
}

View File

@ -61,7 +61,6 @@ const VerticalNavHeader = (props: Props) => {
) : (
<Link href='/' passHref>
<StyledLink>
<img width={30} height={25} src= "https://s6.imgcdn.dev/ttLwl.png"/>
<HeaderTitle variant='h6' sx={{ ml: 3 }}>
{themeConfig.templateName}
</HeaderTitle>

View File

@ -4,20 +4,26 @@ import Table from 'mdi-material-ui/Table'
import CubeOutline from 'mdi-material-ui/CubeOutline'
import HomeOutline from 'mdi-material-ui/HomeOutline'
import SettingsApplicationsIcon from '@mui/icons-material/SettingsApplications';
import ListIcon from '@mui/icons-material/List';
// ** Type import
import { VerticalNavItemsType } from '../../core/layouts/types'
import { BankTransfer, Cart, Clipboard, PageFirst, StarOutline } from 'mdi-material-ui'
import { DocumentScanner, FileOpen, OpenInBrowser, Settings, WebAsset } from '@mui/icons-material'
import { DocumentScanner, FileOpen, LockPerson, OpenInBrowser, People, PeopleOutline, Settings, WebAsset } from '@mui/icons-material'
import { useState, useEffect } from 'react'
const navigation = (): VerticalNavItemsType => {
const [isStripeOnboarded, setIsStripeOnboarded] = useState(false);
const [profileData, setProfileData] = useState(null);
const [userData, setUserData] = useState(null);
const [isAdmin, setIsAdmin] = useState(false);
const getData = async () => {
const adminCheck = await fetch('/api/admin/check', { method: "GET" });
if (adminCheck.status === 200) {
setIsAdmin(true);
}
const onboardCheckRequest = await fetch('/api/artist/onboarded', { method: "GET" });
const onboardCheckResponse = await onboardCheckRequest.json();
setIsStripeOnboarded(onboardCheckResponse["onboarded"]);
@ -37,22 +43,14 @@ const navigation = (): VerticalNavItemsType => {
}, []);
var result = [
{
sectionTitle: 'Admin'
},
{
title: 'Artist Requests',
icon: Clipboard,
path: '/dashboard/admin/requests'
},
{
sectionTitle: 'General'
},
{
title: 'Dashboard',
icon: HomeOutline,
path: '/dashboard'
},
{
sectionTitle: 'General'
},
{
title: 'Account Settings',
icon: Settings,
@ -60,11 +58,34 @@ const navigation = (): VerticalNavItemsType => {
},
{
title: 'Your Requests',
icon: Cart,
icon: ListIcon,
path: '/dashboard/requests'
}
];
if (isAdmin) {
result.push(
{
sectionTitle: 'Admin'
},
{
title: 'Manage Artist Access',
icon: LockPerson,
path: '/dashboard/admin/requests'
},
{
title: 'Manage Users',
icon: People,
path: '/dashboard/admin/users'
},
{
title: 'Manage Artists',
icon: PeopleOutline,
path: '/dashboard/admin/artists'
},
);
}
if (isStripeOnboarded) {
result.push(
{
@ -77,7 +98,7 @@ const navigation = (): VerticalNavItemsType => {
},
{
title: 'Incoming Requests',
icon: CubeOutline,
icon: ListIcon,
path: '/dashboard/artist/requests'
},
{

100
package-lock.json generated
View File

@ -17,13 +17,17 @@
"@mui/x-data-grid": "^6.19.4",
"@mui/x-date-pickers": "^6.19.4",
"@novu/notification-center": "^0.22.0",
"@types/formidable": "^3.4.5",
"apexcharts": "^3.45.2",
"axios": "^1.6.7",
"busboy": "^1.6.0",
"dayjs": "^1.11.10",
"formidable": "^3.5.1",
"jwt-decode": "^4.0.0",
"mdi-material-ui": "^7.8.0",
"mui-color-input": "^2.0.2",
"next": "latest",
"node-fetch": "^3.3.2",
"nprogress": "^0.2.0",
"openapi-typescript-fetch": "^1.1.3",
"react": "^18.2.0",
@ -1271,11 +1275,18 @@
}
}
},
"node_modules/@types/formidable": {
"version": "3.4.5",
"resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-3.4.5.tgz",
"integrity": "sha512-s7YPsNVfnsng5L8sKnG/Gbb2tiwwJTY1conOkJzTMRvJAlLFW1nEua+ADsJQu8N1c0oTHx9+d5nqg10WuT9gHQ==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": {
"version": "18.19.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.10.tgz",
"integrity": "sha512-IZD8kAM02AW1HRDTPOlz3npFava678pr8Ie9Vp8uRhBROXAv8MXT2pCnGZZAKYdromsNQLHQcfWQ6EOatVLtqA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
@ -1590,6 +1601,14 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/data-uri-to-buffer": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
"engines": {
"node": ">= 12"
}
},
"node_modules/date-fns": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.3.1.tgz",
@ -1728,6 +1747,28 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/fetch-blob": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "paypal",
"url": "https://paypal.me/jimmywarting"
}
],
"dependencies": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
}
},
"node_modules/find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
@ -1765,6 +1806,17 @@
"node": ">= 6"
}
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"dependencies": {
"fetch-blob": "^3.1.2"
},
"engines": {
"node": ">=12.20.0"
}
},
"node_modules/formidable": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.1.tgz",
@ -2120,6 +2172,41 @@
}
}
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-fetch": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
"dependencies": {
"data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
}
},
"node_modules/nprogress": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
@ -2791,8 +2878,7 @@
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
},
"node_modules/url-join": {
"version": "4.0.1",
@ -2865,6 +2951,14 @@
"loose-envify": "^1.0.0"
}
},
"node_modules/web-streams-polyfill": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"engines": {
"node": ">= 8"
}
},
"node_modules/webfontloader": {
"version": "1.6.28",
"resolved": "https://registry.npmjs.org/webfontloader/-/webfontloader-1.6.28.tgz",

View File

@ -18,13 +18,17 @@
"@mui/x-data-grid": "^6.19.4",
"@mui/x-date-pickers": "^6.19.4",
"@novu/notification-center": "^0.22.0",
"@types/formidable": "^3.4.5",
"apexcharts": "^3.45.2",
"axios": "^1.6.7",
"busboy": "^1.6.0",
"dayjs": "^1.11.10",
"formidable": "^3.5.1",
"jwt-decode": "^4.0.0",
"mdi-material-ui": "^7.8.0",
"mui-color-input": "^2.0.2",
"next": "latest",
"node-fetch": "^3.3.2",
"nprogress": "^0.2.0",
"openapi-typescript-fetch": "^1.1.3",
"react": "^18.2.0",

View File

@ -1,103 +0,0 @@
// ** React Imports
import { SyntheticEvent, useState } from 'react'
// ** MUI Imports
import Box from '@mui/material/Box'
import Card from '@mui/material/Card'
import TabList from '@mui/lab/TabList'
import TabPanel from '@mui/lab/TabPanel'
import TabContext from '@mui/lab/TabContext'
import { styled } from '@mui/material/styles'
import MuiTab, { TabProps } from '@mui/material/Tab'
// ** Icons Imports
import AccountOutline from 'mdi-material-ui/AccountOutline'
import LockOpenOutline from 'mdi-material-ui/LockOpenOutline'
import InformationOutline from 'mdi-material-ui/InformationOutline'
// ** Demo Tabs Imports
import TabInfo from '../../views/account-settings/TabInfo'
import TabAccount from '../../views/account-settings/TabAccount'
import TabSecurity from '../../views/account-settings/TabSecurity'
// ** Third Party Styles Imports
import 'react-datepicker/dist/react-datepicker.css'
const Tab = styled(MuiTab)<TabProps>(({ theme }) => ({
[theme.breakpoints.down('md')]: {
minWidth: 100
},
[theme.breakpoints.down('sm')]: {
minWidth: 67
}
}))
const TabName = styled('span')(({ theme }) => ({
lineHeight: 1.71,
fontSize: '0.875rem',
marginLeft: theme.spacing(2.4),
[theme.breakpoints.down('md')]: {
display: 'none'
}
}))
const AccountSettings = () => {
// ** State
const [value, setValue] = useState<string>('account')
const handleChange = (event: SyntheticEvent, newValue: string) => {
setValue(newValue)
}
return (
<Card>
<TabContext value={value}>
<TabList
onChange={handleChange}
aria-label='account-settings tabs'
sx={{ borderBottom: theme => `1px solid ${theme.palette.divider}` }}
>
<Tab
value='account'
label={
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<AccountOutline />
<TabName>Account</TabName>
</Box>
}
/>
<Tab
value='security'
label={
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<LockOpenOutline />
<TabName>Security</TabName>
</Box>
}
/>
<Tab
value='info'
label={
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<InformationOutline />
<TabName>Info</TabName>
</Box>
}
/>
</TabList>
<TabPanel sx={{ p: 0 }} value='account'>
<TabAccount />
</TabPanel>
<TabPanel sx={{ p: 0 }} value='security'>
<TabSecurity />
</TabPanel>
<TabPanel sx={{ p: 0 }} value='info'>
<TabInfo />
</TabPanel>
</TabContext>
</Card>
)
}
export default AccountSettings

View File

@ -1,37 +0,0 @@
import { useEffect, useState } from "react";
import { useUser } from "@auth0/nextjs-auth0/client";
import Layout from "../../components/Old/layout";
const ApiProfile = () => {
const { user, isLoading } = useUser();
const [data, setData] = useState(null);
useEffect(() => {
(async () => {
const res = await fetch("/api/protected-api");
const data = await res.json();
setData(data);
})();
}, []);
return (
<Layout user={user} loading={isLoading}>
<h1>Profile</h1>
<div>
<h3>Public page (client rendered)</h3>
<p>We are fetching data on the client-side :</p>
<p>By making request to '/api/protected-api' serverless function</p>
<p>so without a valid session cookie will fail</p>
<p>{JSON.stringify(data)}</p>
</div>
</Layout>
);
};
// Public route.(CSR) also accessing API from the client-side.
// data is not cached when redirecting between pages.
export default ApiProfile;

View File

@ -1,26 +0,0 @@
import { withPageAuthRequired } from "@auth0/nextjs-auth0";
import Layout from "../../components/Old/layout";
import { User } from "../../interfaces";
type ProfileProps = {
user: User;
};
export default function Profile({ user }: ProfileProps) {
return (
<Layout user={user}>
<h1>Profile</h1>
<div>
<h3>Profile (server rendered)</h3>
<img src={user.picture} alt="user picture" />
<p>nickname: {user.nickname}</p>
<p>name: {user.name}</p>
</div>
</Layout>
);
}
// Protected route, checking authentication status before rendering the page.(SSR)
// It's slower than a static page with client side authentication
export const getServerSideProps = withPageAuthRequired();

View File

@ -0,0 +1,18 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { offset, pageSize } = req.body;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists?offset='+offset+'&pageSize='+pageSize, {
headers: {
"Authorization": `Bearer ${accessToken}`
}
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,18 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { artistId } = req.query;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists/'+artistId, {
headers: {
"Authorization": `Bearer ${accessToken}`
}
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -1,11 +1,11 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function onboardUrl(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { userId } = req.query;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtistRequests/'+userId, {
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists/'+userId+"/Suspend", {
headers: {
"Authorization": `Bearer ${accessToken}`,
"Authorization": `Bearer ${accessToken}`
},
method: req.method
});

View File

@ -0,0 +1,19 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { userId } = req.query;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists/'+userId+"/Terminate", {
headers: {
"Authorization": `Bearer ${accessToken}`
},
method: req.method
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,19 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { userId } = req.query;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists/'+userId+"/Unsuspend", {
headers: {
"Authorization": `Bearer ${accessToken}`
},
method: req.method
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,16 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists/Count', {
headers: {
"Authorization": `Bearer ${accessToken}`
}
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

12
pages/api/admin/check.tsx Normal file
View File

@ -0,0 +1,12 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtistRequests', {
headers: {
"Authorization": `Bearer ${accessToken}`
}
});
res.status(response.status).json({})
});

View File

@ -1,8 +1,9 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function onboardUrl(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtistRequests', {
const { offset, pageSize } = req.body;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtistRequests?offset='+offset+'&pageSize='+pageSize, {
headers: {
"Authorization": `Bearer ${accessToken}`
}

View File

@ -0,0 +1,17 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { requestId } = req.query;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtistRequests/'+requestId, {
headers: {
"Authorization": `Bearer ${accessToken}`,
},
method: req.method
});
console.log(response)
let result = await response.json();
res.status(200).json(result);
});
// handles ACCEPT AND DENY

View File

@ -0,0 +1,16 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtistRequests/Count', {
headers: {
"Authorization": `Bearer ${accessToken}`
}
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

18
pages/api/admin/users.tsx Normal file
View File

@ -0,0 +1,18 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { offset, pageSize } = req.body;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers?offset='+offset+'&pageSize='+pageSize, {
headers: {
"Authorization": `Bearer ${accessToken}`
}
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,18 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { userId } = req.query;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/'+userId, {
headers: {
"Authorization": `Bearer ${accessToken}`
}
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,19 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { userId } = req.query;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/'+userId+"/Ban", {
headers: {
"Authorization": `Bearer ${accessToken}`
},
method: req.method
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,19 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { userId } = req.query;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/'+userId+"/Suspend", {
headers: {
"Authorization": `Bearer ${accessToken}`
},
method: req.method
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,19 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { userId } = req.query;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/'+userId+"/Unban", {
headers: {
"Authorization": `Bearer ${accessToken}`
},
method: req.method
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,19 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { userId } = req.query;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/'+userId+"/Unsuspend", {
headers: {
"Authorization": `Bearer ${accessToken}`
},
method: req.method
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,16 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminUsers/Count', {
headers: {
"Authorization": `Bearer ${accessToken}`
}
});
if(response.ok==false){
res.status(200).json({})
return;
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,16 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function products(req, res) {
const { accessToken } = await getAccessToken(req, res);
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Artist', {
headers: {
"Authorization": `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
method: 'POST',
body: req.body
});
let result = await response.json();
res.status(200).json(result);
});

View File

@ -7,7 +7,9 @@ export default withApiAuthRequired(async function onboardUrl(req, res) {
"Authorization": `Bearer ${accessToken}`
}
});
if(response.ok==false){
res.status(200).json({})
}
let result = await response.json();
res.status(200).json(result);
});

View File

@ -1,6 +1,6 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function products(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Accept', {

View File

@ -0,0 +1,22 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
import { IncomingForm } from 'formidable';
import fs from 'fs/promises';
async function createBlobFromFile(path: string): Promise<Blob> {
const file = await fs.readFile(path);
return new Blob([file]);
}
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Assets', {
headers: {
"Authorization": `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
method: req.method
});
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,24 @@
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
import axios from 'axios';
import fs from 'fs';
import path from 'path';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const assetId = req.query.assetId;
const response = await axios({
method: 'get',
url: `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Artist/${requestId}/Assets/${assetId}`,
responseType: 'stream',
headers: {
"Authorization": `Bearer ${accessToken}`,
}
})
res.setHeader('Content-Type', response.headers['content-type']);
// Pipe the response stream directly to the response of the Next.js API Route
response.data.pipe(res);
});

View File

@ -1,6 +1,6 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function products(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Complete', {

View File

@ -1,6 +1,6 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function products(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Deny', {

View File

@ -0,0 +1,16 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId, {
headers: {
"Authorization": `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
method: 'GET'
});
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,52 @@
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
import { IncomingForm } from 'formidable'
import fs from 'fs/promises';
export const config = {
api: {
bodyParser: false,
},
};
async function createBlobFromFile(path: string): Promise<Blob> {
const file = await fs.readFile(path);
return new Blob([file]);
}
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const form = new IncomingForm();
const requestId = req.query.requestId;
form.parse(req, async (err, fields, files) => {
if (err) {
console.error('Error parsing form:', err);
res.status(500).json({ error: 'Error parsing form' });
return;
}
const file = files["newImage"]; // Assuming your file input field name is 'file'
try {
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Assets', {
method: 'POST',
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": " application/octet-stream"
},
body: await createBlobFromFile(file[0].filepath) // Don't set Content-Type, FormData will handle it
});
(response)
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'Failed to upload file');
}
const responseData = await response.json();
res.status(200).json(responseData);
} catch (error) {
console.error('Error uploading file:', error);
res.status(500).json({ error: 'Error uploading file' });
}
});
});

View File

@ -0,0 +1,22 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
import { IncomingForm } from 'formidable';
import fs from 'fs/promises';
async function createBlobFromFile(path: string): Promise<Blob> {
const file = await fs.readFile(path);
return new Blob([file]);
}
export default withApiAuthRequired(async function products(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/References', {
headers: {
"Authorization": `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
method: req.method
});
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,24 @@
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
import axios from 'axios';
import fs from 'fs';
import path from 'path';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const referenceId = req.query.referenceId;
const response = await axios({
method: 'get',
url: `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Artist/${requestId}/References/${referenceId}`,
responseType: 'stream',
headers: {
"Authorization": `Bearer ${accessToken}`,
}
})
res.setHeader('Content-Type', response.headers['content-type']);
// Pipe the response stream directly to the response of the Next.js API Route
response.data.pipe(res);
});

View File

@ -1,24 +1,34 @@
import { useRouter } from 'next/router'
import { getAccessToken } from '@auth0/nextjs-auth0';
import fetch from 'node-fetch'; // Import node-fetch for making HTTP requests
export default async function handler(req, res ): Promise<any> {
const { artistName } = req.query;
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Requests/Request`;
export default async function handler(req, res) {
if (req.method === 'POST') {
const url = process.env.NEXT_PUBLIC_API_URL + `/api/Requests/Request`;
const { accessToken } = await getAccessToken(req, res);
const response = await fetch(url,{
try {
const response = await fetch(url, {
method: 'POST',
headers: {
"Authorization": `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: req.body
body: req.body, // Pipe the incoming request directly to the outgoing request
});
//console.log(response)
if (!response.ok) {
throw new Error('Failed to fetch seller');
const errorData = await response.json();
res.status(response.status).json(errorData);
return;
}
let result = await response.json();
const result = await response.json();
res.status(200).json(result);
} catch (error) {
console.error('Error occurred during fetch:', error);
res.status(500).json({ error: 'An error occurred during the request' });
}
} else {
res.status(405).json({ error: 'Method Not Allowed' });
}
}

View File

@ -3,7 +3,7 @@ import { withApiAuthRequired } from "@auth0/nextjs-auth0";
import { getAccessToken } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function me(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
if(req.method !== 'GET') {
////console.log(req.body)
const { accessToken } = await getAccessToken(req, res);

View File

@ -1,6 +1,6 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function onboardUrl(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Customer/Count?completed=${completed}&declined=${declined}&accepted=${accepted}&paid=${paid}&offset=${offset}&pageSize=${pageSize}`;

View File

@ -1,6 +1,6 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function onboardUrl(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const { completed, declined, accepted, paid, offset, pageSize } = req.body;
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Customer?completed=${completed}&declined=${declined}&accepted=${accepted}&paid=${paid}&offset=${offset}&pageSize=${pageSize}`;

View File

@ -0,0 +1,22 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
import { IncomingForm } from 'formidable';
import fs from 'fs/promises';
async function createBlobFromFile(path: string): Promise<Blob> {
const file = await fs.readFile(path);
return new Blob([file]);
}
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Assets', {
headers: {
"Authorization": `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
method: req.method
});
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,24 @@
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
import axios from 'axios';
import fs from 'fs';
import path from 'path';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const assetId = req.query.assetId;
const response = await axios({
method: 'get',
url: `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Customer/${requestId}/Assets/${assetId}`,
responseType: 'stream',
headers: {
"Authorization": `Bearer ${accessToken}`,
}
})
res.setHeader('Content-Type', response.headers['content-type']);
// Pipe the response stream directly to the response of the Next.js API Route
response.data.pipe(res);
});

View File

@ -0,0 +1,16 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId, {
headers: {
"Authorization": `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
method: 'GET'
});
let result = await response.json();
res.status(200).json(result);
});

View File

@ -0,0 +1,52 @@
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
import { IncomingForm } from 'formidable'
import fs from 'fs/promises';
export const config = {
api: {
bodyParser: false,
},
};
async function createBlobFromFile(path: string): Promise<Blob> {
const file = await fs.readFile(path);
return new Blob([file]);
}
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const form = new IncomingForm();
const requestId = req.query.requestId;
form.parse(req, async (err, fields, files) => {
if (err) {
console.error('Error parsing form:', err);
res.status(500).json({ error: 'Error parsing form' });
return;
}
const file = files["newImage"]; // Assuming your file input field name is 'file'
try {
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/References', {
method: 'POST',
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": " application/octet-stream"
},
body: await createBlobFromFile(file[0].filepath) // Don't set Content-Type, FormData will handle it
});
(response)
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'Failed to upload file');
}
const responseData = await response.json();
res.status(200).json(responseData);
} catch (error) {
console.error('Error uploading file:', error);
res.status(500).json({ error: 'Error uploading file' });
}
});
});

View File

@ -1,6 +1,6 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function products(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Payment', {

View File

@ -1,32 +1,22 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
import { IncomingForm } from 'formidable';
import fs from 'fs/promises';
export default withApiAuthRequired(async function products(req, res) {
async function createBlobFromFile(path: string): Promise<Blob> {
const file = await fs.readFile(path);
return new Blob([file]);
}
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
if(req.method == 'GET'){
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+'/References', {
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', {
headers: {
"Authorization": `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
method: req.method,
body: req.body
});
console.log(response)
let result = await response.json();
res.status(200).json(result);
}
});

View File

@ -0,0 +1,24 @@
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
import axios from 'axios';
import fs from 'fs';
import path from 'path';
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const referenceId = req.query.referenceId;
const response = await axios({
method: 'get',
url: `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Customer/${requestId}/References/${referenceId}`,
responseType: 'stream',
headers: {
"Authorization": `Bearer ${accessToken}`,
}
})
res.setHeader('Content-Type', response.headers['content-type']);
// Pipe the response stream directly to the response of the Next.js API Route
response.data.pipe(res);
});

View File

@ -1,6 +1,6 @@
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
export default withApiAuthRequired(async function products(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Review', {

View File

@ -16,13 +16,14 @@ 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 ArtistPortfolio from "../../components/dashboard/artist/portfolio";
import { RouterNetwork } from "mdi-material-ui";
import { useRouter } from "next/router";
import { profile } from "console";
import FileOpen from "@mui/icons-material/FileOpen";
import Reviews from "../../components/dashboard/artist/reviews";
const Profile = () => {
const ArtistBox = () => {
const [profileData, setArtistData] = useState(null);
const [description, setDescription] = useState("");
@ -57,25 +58,29 @@ const Profile = () => {
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
try {
const requestResponse = await fetch('/api/box/newRequest', {
method: 'POST',
body: formData // Pass FormData containing the file
body: JSON.stringify({
artistId: profileData["id"],
message: payload.get('Message'),
amount: payload.get('Amount'),
})
});
if(requestResponse.ok){
router.push("/dashboard/requests")
if (requestResponse.ok) {
const requestResponseData = await requestResponse.json();
router.push("/dashboard/requests/"+requestResponseData["id"]);
} else {
alert("Error submitting request")
const errorData = await requestResponse.json();
alert("Error submitting request: " + errorData.detail);
}
} catch (error) {
console.error('Error submitting request:', error);
alert("Error submitting request. Please try again later.");
}
};
const getData = async () => {
if(router.query.artistName!=null){
@ -92,31 +97,6 @@ const Profile = () => {
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 (
<>
@ -128,15 +108,7 @@ const Profile = () => {
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);
submitRequest(formData);
handleClose();
},
}}
@ -150,8 +122,8 @@ const Profile = () => {
autoFocus
required
margin="dense"
id="name"
name="message"
id="Message"
name="Message"
label="Request Message"
type="message"
fullWidth
@ -162,9 +134,10 @@ const Profile = () => {
value={requestMessage}
/>
<CurrencyTextField
label="Price"
label="Amount"
variant="standard"
currencySymbol="$"
name="Amount"
outputFormat="number"
decimalCharacter="."
digitGroupSeparator=","
@ -172,29 +145,6 @@ const Profile = () => {
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>
@ -264,19 +214,9 @@ const Profile = () => {
<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]}
/>
{profileData!=null ? (
<Reviews artistId={profileData["id"]}/>
):null}
</Grid>
</Grid>
</CardContent>
@ -312,6 +252,6 @@ const Profile = () => {
};
// Protected route, checking user authentication client-side.(CSR)
export default withPageAuthRequired(Profile);
export default withPageAuthRequired(ArtistBox);

View File

@ -1,83 +0,0 @@
// ** MUI Imports
import Grid from '@mui/material/Grid'
import Typography from '@mui/material/Typography'
// ** Demo Components Imports
import CardUser from '../views/cards/CardUser'
import CardImgTop from '../views/cards/CardImgTop'
import CardMobile from '../views/cards/CardMobile'
import CardSupport from '../views/cards/CardSupport'
import CardTwitter from '../views/cards/CardTwitter'
import CardFacebook from '../views/cards/CardFacebook'
import CardLinkedIn from '../views/cards/CardLinkedIn'
import CardAppleWatch from '../views/cards/CardAppleWatch'
import CardMembership from '../views/cards/CardMembership'
import CardInfluencer from '../views/cards/CardInfluencer'
import CardNavigation from '../views/cards/CardNavigation'
import CardWithCollapse from '../views/cards/CardWithCollapse'
import CardVerticalRatings from '../views/cards/CardVerticalRatings'
import CardNavigationCenter from '../views/cards/CardNavigationCenter'
import CardHorizontalRatings from '../views/cards/CardHorizontalRatings'
const CardBasic = () => {
return (
<Grid container spacing={6}>
<Grid item xs={12} sx={{ paddingBottom: 4 }}>
<Typography variant='h5'>Basic Cards</Typography>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardImgTop />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardUser />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardWithCollapse />
</Grid>
<Grid item xs={12} sm={6}>
<CardMobile />
</Grid>
<Grid item xs={12} sm={6}>
<CardHorizontalRatings />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardAppleWatch />
</Grid>
<Grid item xs={12} md={8}>
<CardMembership />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardInfluencer />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardVerticalRatings />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardSupport />
</Grid>
<Grid item xs={12} sx={{ pb: 4, pt: theme => `${theme.spacing(17.5)} !important` }}>
<Typography variant='h5'>Navigation Cards</Typography>
</Grid>
<Grid item xs={12} md={6}>
<CardNavigation />
</Grid>
<Grid item xs={12} md={6}>
<CardNavigationCenter />
</Grid>
<Grid item xs={12} sx={{ pb: 4, pt: theme => `${theme.spacing(17.5)} !important` }}>
<Typography variant='h5'>Solid Cards</Typography>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardTwitter />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardFacebook />
</Grid>
<Grid item xs={12} sm={6} md={4}>
<CardLinkedIn />
</Grid>
</Grid>
)
}
export default CardBasic

View File

@ -0,0 +1,151 @@
import * as React from 'react';
import { DataGrid } from '@mui/x-data-grid';
import { GridColDef } from '@mui/x-data-grid';
import TextField from '@mui/material/TextField';
import { Button, Stack, Typography } from '@mui/material';
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
import { DateField } from '@mui/x-date-pickers/DateField';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import Chip from '@mui/material/Chip';
import {Block, Check, Close, Download, OpenInFull, OpenInNew, Refresh, Star, Upload } from '@mui/icons-material';
import PriceCheckIcon from '@mui/icons-material/PriceCheck';
import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn';
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
import ShoppingCartCheckoutIcon from '@mui/icons-material/ShoppingCartCheckout';
import { IconButton } from '@mui/material';
import Tooltip from '@mui/material/Tooltip';
import { Card, CardContent } from '@mui/material';
import Rating from '@mui/material/Rating';
import dayjs from 'dayjs';
import { DownloadBox, Magnify, StarOutline } from 'mdi-material-ui';
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material';
import { Grid } from '@mui/material';
import { useRouter } from 'next/router';
import { request } from 'http';
import { useMediaQuery } from '@mui/material';
export default function AdminArtists() {
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm')); // Check if the screen size is small
const router = useRouter();
let columns = [];
if(isSmallScreen){
columns = [
{ field: 'id', headerName: '', flex: 0.05, sortable: false, filterable: false},
];
}
else{
columns = [
{ field: 'id', headerName: '', flex: 0.05, sortable: false, filterable: false},
{ field: 'displayName', headerName: 'User Name', flex: 0.15, sortable: false, filterable: false, valueGetter: (params) => {
return params.row.user.displayName
}},
{ field: 'name', headerName: 'Artist Name', flex: 0.15, sortable: false, filterable: false, valueGetter: (params) => {
return params.row.name
}},
{ field: 'email', headerName: 'Email', flex: 0.15, sortable: false, filterable: false, valueGetter: (params) => {
return params.row.user.email
}},
{ field: 'numberOfRequests', headerName: '# of Requests', flex: 0.1, sortable: false, filterable: false},
{ field: 'averageRating', headerName: 'Average Rating', flex: 0.1, sortable: false, filterable: false},
{ field: 'amountMade', headerName: 'Amount Made', flex: 0.1, sortable: false, filterable: false},
{ field: 'feesCollected', headerName: 'Fees Collected', flex: 0.1, sortable: false, filterable: false},
{ field: 'status', headerName: 'Status', flex: 0.1, sortable: false, filterable: false, renderCell: (params) =>{
if(params.row.user.banned){
return <Chip icon={<Block />} label="Banned" variant="outlined" color="error" />
}
else if(params.row.suspended || params.row.user.suspended){
return <Chip icon={<Block />} label="Suspended" variant="outlined" color="error" />
}
else{
return <Chip icon={<Check />} label="Active" variant="outlined" color="success" />
}
}},
{ field: 'actions', headerName: '', flex: 0.05, sortable: false, filterable: false, renderCell: (params) => {
return <Tooltip title="View more information about this user."><IconButton color="info" onClick={() => router.push("/dashboard/admin/artists/"+params.row.id)}><OpenInNew /></IconButton></Tooltip>
}}
];
}
const [isLoading, setIsLoading] = React.useState(true);
const [requestCount, setRequestCount] = React.useState(null);
const [requestData, setRequestData] = React.useState({});
const [paginationModel, setPaginationModel] = React.useState({
page: 0,
pageSize: 15,
});
const getRequests = async () => {
setIsLoading(true);
const response = await fetch('/api/admin/artists', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
completed: true, // Example query parameter
declined: true, // Example query parameter
accepted: true, // Example query parameter
paid: true, // Example query parameter
offset: paginationModel.page*paginationModel.pageSize, // Example query parameter
pageSize: paginationModel.pageSize
}),
});
const data = await response.json();
setRequestData(data);
setIsLoading(false);
}
const getRequestsCount = async () => {
const response = await fetch('/api/admin/artists/count', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
completed: true, // Example query parameter
declined: true, // Example query parameter
accepted: true, // Example query parameter
paid: true, // Example query parameter
offset: paginationModel.page*paginationModel.pageSize, // Example query parameter
pageSize: paginationModel.pageSize
})
});
const data = await response.json();
setRequestCount(data);
setRowCountState((prevRowCountState) =>
data !== undefined
? data
: prevRowCountState,
);
return data;
}
// Some API clients return undefined while loading
// Following lines are here to prevent `rowCountState` from being undefined during the loading
const [rowCountState, setRowCountState] = React.useState(0);
React.useEffect(() => {
getRequests();
getRequestsCount();
}, [requestCount, setRowCountState,paginationModel]);
return (
<div style={{ height: '100%', width: '100%' }}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DataGrid
rows={requestData}
columns={columns}
rowCount={rowCountState}
loading={isLoading}
pageSizeOptions={[15]}
paginationModel={paginationModel}
paginationMode="server"
onPaginationModelChange={setPaginationModel}
/>
</LocalizationProvider>
</div>
);
}

View File

@ -0,0 +1,104 @@
import * as React from 'react';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'
import { Alert, Card, CardContent, Grid, IconButton, TextField, Typography } from '@mui/material';
import { ArrowBack, ArrowLeft, Block, Close } from '@mui/icons-material';
import Button from '@mui/material/Button';
import { OpenInNew } from 'mdi-material-ui';
import Tooltip from '@mui/material/Tooltip';
const AdminArtist = () => {
const router = useRouter();
const [artist, setArtist] = useState(null);
const getData = async () => {
if(router.query.artistId!=null){
const response = await fetch("/api/admin/artists/"+router.query.artistId);
const data = await response.json();
setArtist(data);
}
}
useEffect(() => {
getData()
}, [router.query.artistId]);
return (
<>
<Card>
<CardContent>
<Grid container spacing={3}>
<Grid item xs={6}>
<Typography variant="h5">Artist Information</Typography>
</Grid>
<Grid item xs={6} sx={{textAlign:"right"}}>
<Tooltip title="Ban this artist.">
<IconButton color="error">
<Block/>
</IconButton>
</Tooltip>
<Tooltip title="Suspend this artist.">
<IconButton color="warning">
<Close/>
</IconButton>
</Tooltip>
<Tooltip title="Go back a page.">
<IconButton onClick={() => router.push("/dashboard/admin/artists")} color="primary">
<ArrowBack/>
</IconButton>
</Tooltip>
</Grid>
<Grid item xs={12} md={6}>
<Grid container spacing={3}>
<Grid item xs={12} md={5}>
<Grid container spacing={3}>
<Grid item xs={12}>
Display Name: {artist?.user?.displayName}
</Grid>
<Grid item xs={12}>
Email: {artist?.user?.email}
</Grid>
<Grid item xs={12}>
<Button variant="contained" color="primary" fullWidth>Save Changes</Button>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={7}>
<TextField size="small" label="Admin Notes" multiline rows={4} fullWidth variant="outlined" value={artist?.userId} />
</Grid>
<Grid item xs={12}>
<Alert severity={artist?.numberOfBans > 0 ? "error" : "success"}>{artist?.numberOfBans > 0 ? "This user has been banned "+artist?.numberOfBans+" times." : "This user has not been banned before."}</Alert>
</Grid>
<Grid item xs={12}>
<Alert severity={artist?.numberOfSuspensions > 0 ? "error" : "success"}>{artist?.numberOfBans > 0 ? "This user has been suspended "+artist?.numberOfSuspensions+" times." : "This user has not been suspended before."}</Alert>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={6}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Alert severity="success">This artist has made ${artist?.amountMade}, and we have made ${artist?.feesCollected} in fees.</Alert>
</Grid>
<Grid item xs={12}>
<Alert severity={artist?.numberOfRequests > 0 ? "success" : "warning"}>This artist has accepted {artist?.numberOfRequests} requests.</Alert>
</Grid>
<Grid item xs={12}>
<Alert severity={artist?.numberOfCompleted > 0 ? "success" : "warning"}>This artist has completed {artist?.numberOfCompleted} requests.</Alert>
</Grid>
</Grid>
</Grid>
</Grid>
</CardContent>
</Card>
</>
);
};
// Protected route, checking user authentication client-side.(CSR)
export default withPageAuthRequired(AdminArtist);

View File

@ -1,50 +1,206 @@
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 * 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 from '@mui/material/Button';
import Switch from '@mui/material/Switch';
import Divider from '@mui/material/Divider';
import ArtistRequest from "../../../components/ArtistRequest";
import { Button, Stack, Typography } from '@mui/material';
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
import { DateField } from '@mui/x-date-pickers/DateField';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import Chip from '@mui/material/Chip';
import {Block, Check, Close, Download, OpenInFull, OpenInNew, Person, Refresh, Star, Upload } from '@mui/icons-material';
import PriceCheckIcon from '@mui/icons-material/PriceCheck';
import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn';
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
import ShoppingCartCheckoutIcon from '@mui/icons-material/ShoppingCartCheckout';
import { IconButton } from '@mui/material';
import Tooltip from '@mui/material/Tooltip';
import { Card, CardContent } from '@mui/material';
import Rating from '@mui/material/Rating';
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
import dayjs from 'dayjs';
import { DownloadBox, Magnify, StarOutline } from 'mdi-material-ui';
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material';
import { Grid } from '@mui/material';
import { useRouter } from 'next/router';
import { request } from 'http';
import { useMediaQuery } from '@mui/material';
export default function AdminRequests() {
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm')); // Check if the screen size is small
const router = useRouter();
let columns = [];
if(isSmallScreen){
columns = [
{ field: 'id', headerName: '', flex: 0.05, sortable: false, filterable: false},
{ field: 'message', headerName: 'Message', flex: 0.2, sortable: false, filterable: false},
{ field: 'actions', headerName: '', flex: 0.15, sortable: false, filterable: false, renderCell: (params) => {
const handleAccept = async () => {
var response = await fetch("/api/admin/requests/"+params.row.userId, {method:"PUT"})
if(response.ok){
var data = await response.json();
router.reload();
}
else{
alert("Failed to accept request.")
}
}
const handleDeny = async () => {
var response = await fetch("/api/admin/requests/"+params.row.userId, {method:"DELETE"})
if(response.ok){
var data = await response.json();
router.reload();
}
else{
alert("Failed to deny request.")
}
}
if(params.row.accepted){
return <>
<Tooltip title="Revoke artist access"><IconButton color="error"><Block/></IconButton></Tooltip>
<Tooltip title="View artist information"><IconButton onClick={() => router.push("/dashboard/admin/requests/"+params.row.id)} color="info"><Magnify/></IconButton></Tooltip>
</>
}
else{
return (
<ArtistRequest userid={request["userId"]} id={request["id"]} username={""} message={request["message"]} date={formattedTime} reload={getData} />
<>
<Tooltip title="Accept this request and grant artist access."><IconButton onClick={handleAccept} color="success"><Check/></IconButton></Tooltip>
<Tooltip title="Decline this request and refuse artist access."><IconButton onClick={handleDeny} color="error"><Close/></IconButton></Tooltip>
</>
)
}
))
):(<Typography>No requests</Typography>)}
</Grid>
);
};
}}
];
}
else{
columns = [
{ field: 'id', headerName: '', flex: 0.05, sortable: false, filterable: false},
{ field: 'userId', headerName: 'User ID', flex: 0.25, sortable: false, filterable: false},
{ field: 'message', headerName: 'Message', flex: 0.5, sortable: false, filterable: false},
{ field: 'requestDate', headerName: 'Request Date', flex: 0.1, sortable: false, filterable: false, type: 'date', valueGetter: (params) => { return new Date(params.row.requestDate); }},
{ field: 'accepted', headerName:'Accepted', flex: 0.15, sortable: false, filterable: false, renderCell: (params) => {
return (params.row.accepted ? <Chip icon={<Check />} label="Accepted" variant="outlined" color="success" /> : <Chip icon={<Refresh />} label="Pending" variant="outlined" color="info" />)
}},
{ field: 'actions', headerName: '', flex: 0.15, sortable: false, filterable: false, renderCell: (params) => {
const handleAccept = async () => {
var response = await fetch("/api/admin/requests/"+params.row.userId, {method:"PUT"})
if(response.ok){
var data = await response.json();
router.reload();
}
else{
alert("Failed to accept request.")
}
}
const handleDeny = async () => {
var response = await fetch("/api/admin/requests/"+params.row.userId, {method:"DELETE"})
if(response.ok){
var data = await response.json();
router.reload();
}
else{
alert("Failed to deny request.")
}
}
if(params.row.accepted){
return <>
<Tooltip title="View request information"><IconButton onClick={() => router.push("/dashboard/admin/requests/"+params.row.id)} color="info"><OpenInNew/></IconButton></Tooltip>
<Tooltip title="View artist information"><IconButton onClick={() => router.push("/dashboard/admin/users/"+params.row.id)} color="info"><Person/></IconButton></Tooltip>
</>
}
else{
// Protected route, checking user authentication client-side.(CSR)
export default withPageAuthRequired(ArtistRequests);
return (
<>
<Tooltip title="View request information"><IconButton onClick={() => router.push("/dashboard/admin/requests/"+params.row.id)} color="info"><OpenInNew/></IconButton></Tooltip>
<Tooltip title="Accept this request and grant artist access."><IconButton onClick={handleAccept} color="success"><Check/></IconButton></Tooltip>
<Tooltip title="Decline this request and refuse artist access."><IconButton onClick={handleDeny} color="error"><Close/></IconButton></Tooltip>
</>
)
}
}}
];
}
const [isLoading, setIsLoading] = React.useState(true);
const [requestCount, setRequestCount] = React.useState(null);
const [requestData, setRequestData] = React.useState({});
const [paginationModel, setPaginationModel] = React.useState({
page: 0,
pageSize: 15,
});
const getRequests = async () => {
setIsLoading(true);
const response = await fetch('/api/admin/requests', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
completed: true, // Example query parameter
declined: true, // Example query parameter
accepted: true, // Example query parameter
paid: true, // Example query parameter
offset: paginationModel.page*paginationModel.pageSize, // Example query parameter
pageSize: paginationModel.pageSize
}),
});
const data = await response.json();
setRequestData(data);
setIsLoading(false);
}
const getRequestsCount = async () => {
const response = await fetch('/api/admin/requests/count', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
completed: true, // Example query parameter
declined: true, // Example query parameter
accepted: true, // Example query parameter
paid: true, // Example query parameter
offset: paginationModel.page*paginationModel.pageSize, // Example query parameter
pageSize: paginationModel.pageSize
})
});
const data = await response.json();
setRequestCount(data);
setRowCountState((prevRowCountState) =>
data !== undefined
? data
: prevRowCountState,
);
return data;
}
// Some API clients return undefined while loading
// Following lines are here to prevent `rowCountState` from being undefined during the loading
const [rowCountState, setRowCountState] = React.useState(0);
React.useEffect(() => {
getRequests();
getRequestsCount();
}, [requestCount, setRowCountState,paginationModel]);
return (
<div style={{ height: '100%', width: '100%' }}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DataGrid
rows={requestData}
columns={columns}
rowCount={rowCountState}
loading={isLoading}
pageSizeOptions={[15]}
paginationModel={paginationModel}
paginationMode="server"
onPaginationModelChange={setPaginationModel}
/>
</LocalizationProvider>
</div>
);
}

View File

@ -0,0 +1,124 @@
import * as React from 'react';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'
import { Alert, Card, CardContent, Grid, IconButton, TextField, Typography } from '@mui/material';
import Button from '@mui/material/Button';
import { OpenInNew } from 'mdi-material-ui';
import Tooltip from '@mui/material/Tooltip';
import { ArrowBack } from '@mui/icons-material';
const AdminRequest = () => {
const router = useRouter();
const [request, setRequest] = useState(null);
const getData = async () => {
if(router.query.requestId!=null){
const response = await fetch("/api/admin/requests/"+router.query.requestId);
const data = await response.json();
setRequest(data);
}
}
const handleAccept = async () => {
var response = await fetch("/api/admin/requests/"+router.query.requestId, {method:"PUT"})
if(response.ok){
var data = await response.json();
router.reload();
}
else{
alert("Failed to accept request.")
}
}
const handleDeny = async () => {
var response = await fetch("/api/admin/requests/"+router.query.requestId, {method:"DELETE"})
if(response.ok){
var data = await response.json();
router.reload();
}
else{
alert("Failed to deny request.")
}
}
useEffect(() => {
getData()
}, [router.query.requestId]);
let formattedTime = ""
const date = new Date(request?.requestDate);
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
return (
<>
<Card>
<CardContent>
<Grid container>
<Grid item xs={6}>
<Typography variant="h5">{router.query.requestId} - Artist Access Request</Typography>
</Grid>
<Grid item xs={6} sx={{textAlign:"right"}}>
<Tooltip title="Go back a page.">
<IconButton onClick={() => router.push("/dashboard/admin/requests")} color="primary">
<ArrowBack/>
</IconButton>
</Tooltip>
</Grid>
<Grid item xs={6}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Alert severity="info">Submitted on {formattedTime}</Alert>
</Grid>
{request?.accepted ? (
<Grid item xs={12}>
<Alert severity="success">This artist access request has been accepted.</Alert>
</Grid>
):(
<Grid item xs={12}>
<Alert severity="warning">Pending review from platform administrator.</Alert>
</Grid>
)}
<Grid item xs={12}>
<TextField
id="outlined-multiline-static"
label="Message"
multiline
rows={4}
fullWidth
value={request?.message}
disabled>
{request?.message}
</TextField>
</Grid>
{request?.accepted ? (
<Grid item xs={12} md={12}>
<Button fullWidth variant="contained" onClick={handleAccept} color="error">Revoke Artist Access</Button>
</Grid>
):(
<>
<Grid item xs={12} md={6}>
<Button fullWidth variant="contained" onClick={handleAccept} color="primary">Accept</Button>
</Grid>
<Grid item xs={12} md={6}>
<Button fullWidth variant="contained" onClick={handleDeny} color="secondary">Reject</Button>
</Grid>
</>
)}
</Grid>
</Grid>
<Grid item xs={6}>
</Grid>
</Grid>
</CardContent>
</Card>
</>
);
};
// Protected route, checking user authentication client-side.(CSR)
export default withPageAuthRequired(AdminRequest);

View File

@ -0,0 +1,147 @@
import * as React from 'react';
import { DataGrid } from '@mui/x-data-grid';
import { GridColDef } from '@mui/x-data-grid';
import TextField from '@mui/material/TextField';
import { Button, Stack, Typography } from '@mui/material';
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
import { DateField } from '@mui/x-date-pickers/DateField';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import Chip from '@mui/material/Chip';
import {Block, Check, Close, Download, OpenInFull, OpenInNew, Refresh, Star, Upload } from '@mui/icons-material';
import PriceCheckIcon from '@mui/icons-material/PriceCheck';
import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn';
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
import ShoppingCartCheckoutIcon from '@mui/icons-material/ShoppingCartCheckout';
import { IconButton } from '@mui/material';
import Tooltip from '@mui/material/Tooltip';
import { Card, CardContent } from '@mui/material';
import Rating from '@mui/material/Rating';
import dayjs from 'dayjs';
import { DownloadBox, Magnify, StarOutline } from 'mdi-material-ui';
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material';
import { Grid } from '@mui/material';
import { useRouter } from 'next/router';
import { request } from 'http';
import { useMediaQuery } from '@mui/material';
export default function AdminUsers() {
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm')); // Check if the screen size is small
const router = useRouter();
let columns = [];
if(isSmallScreen){
columns = [
{ field: 'id', headerName: 'User ID', flex: 0.95, sortable: false, filterable: false},
{ field: "actions", headerName: "Actions", flex: 0.05, sortable: false, filterable: false, renderCell: (params) => {
return <Tooltip title="View more information about this user."><IconButton color="info" onClick={() => router.push("/dashboard/admin/users/"+params.row.id)}><OpenInNew /></IconButton></Tooltip>
}}
];
}
else{
columns = [
{ field: 'id', headerName: 'User ID', flex: 0.2, sortable: false, filterable: false},
{ field: 'displayName', headerName: 'Display Name', flex: 0.15, sortable: false, filterable: false},
{ field: 'email', headerName: 'Email', flex: 0.2, sortable: false, filterable: false},
{ field: "numberOfRequests", headerName: "# of Requests", flex: 0.1, sortable: false, filterable: false},
{ field: "numberOfReviews", headerName: "# of Reviews", flex: 0.1, sortable: false, filterable: false},
{ field: "amountSpent", headerName: "Amount Spent", flex: 0.1, sortable: false, filterable: false},
{ field: 'status', headerName: 'Status', flex: 0.1, sortable: false, filterable: false, renderCell: (params) =>{
if(params.row.banned){
return <Chip icon={<Block />} label="Banned" variant="outlined" color="error" />
}
else if(params.row.suspended){
return <Chip icon={<Block />} label="Suspended" variant="outlined" color="error" />
}
else{
return <Chip icon={<Check />} label="Active" variant="outlined" color="success" />
}
}},
{ field: "actions", headerName: "", flex: 0.05, sortable: false, filterable: false, renderCell: (params) => {
return <Tooltip title="View more information about this user."><IconButton color="info" onClick={() => router.push("/dashboard/admin/users/"+params.row.id)}><OpenInNew /></IconButton></Tooltip>
}}
];
}
const [isLoading, setIsLoading] = React.useState(true);
const [requestCount, setRequestCount] = React.useState(null);
const [requestData, setRequestData] = React.useState({});
const [paginationModel, setPaginationModel] = React.useState({
page: 0,
pageSize: 15,
});
const getRequests = async () => {
setIsLoading(true);
const response = await fetch('/api/admin/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
completed: true, // Example query parameter
declined: true, // Example query parameter
accepted: true, // Example query parameter
paid: true, // Example query parameter
offset: paginationModel.page*paginationModel.pageSize, // Example query parameter
pageSize: paginationModel.pageSize
}),
});
const data = await response.json();
setRequestData(data);
setIsLoading(false);
}
const getRequestsCount = async () => {
const response = await fetch('/api/admin/users/count', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
completed: true, // Example query parameter
declined: true, // Example query parameter
accepted: true, // Example query parameter
paid: true, // Example query parameter
offset: paginationModel.page*paginationModel.pageSize, // Example query parameter
pageSize: paginationModel.pageSize
})
});
const data = await response.json();
setRequestCount(data);
setRowCountState((prevRowCountState) =>
data !== undefined
? data
: prevRowCountState,
);
return data;
}
// Some API clients return undefined while loading
// Following lines are here to prevent `rowCountState` from being undefined during the loading
const [rowCountState, setRowCountState] = React.useState(0);
React.useEffect(() => {
getRequests();
getRequestsCount();
}, [requestCount, setRowCountState,paginationModel]);
return (
<div style={{ height: '100%', width: '100%' }}>
<Button target="_blank" href="https://manage.auth0.com/dashboard">Open Auth0 Dashboard</Button>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DataGrid
rows={requestData}
columns={columns}
rowCount={rowCountState}
loading={isLoading}
pageSizeOptions={[15]}
paginationModel={paginationModel}
paginationMode="server"
onPaginationModelChange={setPaginationModel}
/>
</LocalizationProvider>
</div>
);
}

View File

@ -0,0 +1,104 @@
import * as React from 'react';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'
import { Alert, Card, CardContent, Grid, IconButton, TextField, Typography } from '@mui/material';
import { ArrowBack, ArrowLeft, Block, Close } from '@mui/icons-material';
import Button from '@mui/material/Button';
import { OpenInNew } from 'mdi-material-ui';
import Tooltip from '@mui/material/Tooltip';
const AdminUser = () => {
const router = useRouter();
const [user, setUser] = useState(null);
const getData = async () => {
if(router.query.userId!=null){
const response = await fetch("/api/admin/users/"+router.query.userId);
const data = await response.json();
setUser(data);
}
}
useEffect(() => {
getData()
}, [router.query.userId]);
return (
<>
<Card>
<CardContent>
<Grid container spacing={3}>
<Grid item xs={6}>
<Typography variant="h5">User Information</Typography>
</Grid>
<Grid item xs={6} sx={{textAlign:"right"}}>
<Tooltip title="Ban this user.">
<IconButton color="error">
<Block/>
</IconButton>
</Tooltip>
<Tooltip title="Suspend this user.">
<IconButton color="warning">
<Close/>
</IconButton>
</Tooltip>
<Tooltip title="Go back a page.">
<IconButton onClick={() => router.push("/dashboard/admin/users")} color="primary">
<ArrowBack/>
</IconButton>
</Tooltip>
</Grid>
<Grid item xs={12} md={6}>
<Grid container spacing={3}>
<Grid item xs={12} md={5}>
<Grid container spacing={3}>
<Grid item xs={12}>
Display Name: {user?.displayName}
</Grid>
<Grid item xs={12}>
Email: {user?.email}
</Grid>
<Grid item xs={12}>
<Button variant="contained" color="primary" fullWidth>Save Changes</Button>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={7}>
<TextField size="small" label="Admin Notes" multiline rows={4} fullWidth variant="outlined" value={user?.userId} />
</Grid>
<Grid item xs={12}>
<Alert severity={user?.numberOfBans > 0 ? "error" : "success"}>{user?.numberOfBans > 0 ? "This user has been banned "+user?.numberOfBans+" times." : "This user has not been banned before."}</Alert>
</Grid>
<Grid item xs={12}>
<Alert severity={user?.numberOfSuspensions > 0 ? "error" : "success"}>{user?.numberOfBans > 0 ? "This user has been suspended "+user?.numberOfSuspensions+" times." : "This user has not been suspended before."}</Alert>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={6}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Alert severity={user?.numberOfRequests > 0 ? "success" : "warning"}>This user has opened {user?.numberOfRequests} requests.</Alert>
</Grid>
<Grid item xs={12}>
<Alert severity={user?.amountSpent > 0 ? "success" : "warning"}>This user has paid {user?.amountSpent} for {user?.numberOfPaid} requests.</Alert>
</Grid>
<Grid item xs={12}>
<Alert severity={user?.numberOfReviews > 0 ? "success" : "warning"}>This user has left {user?.numberOfReviews} reviews on completed requests.</Alert>
</Grid>
</Grid>
</Grid>
</Grid>
</CardContent>
</Card>
</>
);
};
// Protected route, checking user authentication client-side.(CSR)
export default withPageAuthRequired(AdminUser);

View File

@ -2,13 +2,13 @@ import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client";
import { CircularProgress, Grid, IconButton, Tooltip, Typography } from "@mui/material";
import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import EditableArtistPortfolio from "../../../components/editableArtistPortfolio";
import EditableArtistPortfolio from "../../../components/dashboard/artist/editablePortfolio";
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";
import ArtistRequest from "../../../components/dashboard/admin/artistRequest";
import Box from '@mui/material/Box';
import { Save } from "@mui/icons-material";

View File

@ -7,13 +7,13 @@ import CardMedia from '@mui/material/CardMedia';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import { useEffect, useState } from "react";
import EditableArtistPortfolio from "../../../components/editableArtistPortfolio";
import ArtistPortfolio from "../../../components/artistPortfolio";
import EditableArtistPortfolio from "../../../components/dashboard/artist/editablePortfolio";
import ArtistPortfolio from "../../../components/dashboard/artist/portfolio";
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';
import Reviews from "../../../components/reviews";
import Reviews from "../../../components/dashboard/artist/reviews";
const Profile = () => {

View File

@ -21,61 +21,47 @@ 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 RequestReferences from '../../../components/requestReferences';
import { useMediaQuery } from '@mui/material';
export default function ServerPaginationGrid() {
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm')); // Check if the screen size is small
const router = useRouter();
const columns = [
{ field: 'id', headerName: 'ID', flex: 0.1},
{ field: 'status', headerName: 'Status', flex: 0.15,
let columns = []
if(isSmallScreen){
columns = [
{ field: 'id', headerName: 'ID', flex: 0.1, filterable: false, sortable: false},
{ field: 'status', headerName: 'Status', flex: 0.15, filterable: false, sortable: false,
renderCell: (params) => {
if(params.row.completed){
return <Chip icon={<Check />} label="Completed" variant="filled" color="success" />
return <Check color="success" />
}
else if(params.row.paid){
return <Chip icon={<PriceCheckIcon />} label="Paid" variant="filled" color="success" />
return <PriceCheckIcon color="success" />
}
else if(params.row.accepted && params.row.paid==false){
return <Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="filled" color="warning" />
return <PriceCheckIcon color="warning" />
}
else if(params.row.accepted && params.row.paid){
return <Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="filled" color="info" />
return <AssignmentTurnedInIcon color="info" />
}
else if(params.row.declined){
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="filled" color="error" />
return <AssignmentLateIcon color="error" />
}
else{
return <Chip icon={<Refresh />} label="Pending" variant="filled" color="secondary" />
return <Refresh 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) => {
{ field: 'amount', headerName: 'Amount', flex: 0.15, filterable: false, sortable: false, 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,
{ field: 'action', headerName: '', flex:0.1, filterable: false, sortable: false,
renderCell: (params) =>{
const acceptRequest = async () => {
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/accept", { method: 'PUT' })
if(response.status === 200){
router.reload()
router.push("/dashboard/artist/requests/"+params.row["id"])
}
else{
alert("Error accepting request.")
@ -89,7 +75,7 @@ export default function ServerPaginationGrid() {
const denyRequest = async () => {
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/deny", { method: 'PUT' })
if(response.status === 200){
router.reload()
router.push("/dashboard/artist/requests/"+params.row["id"])
}
else{
alert("Error accepting request.")
@ -99,7 +85,7 @@ export default function ServerPaginationGrid() {
const completeRequest = async () => {
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/complete", { method: 'PUT' })
if(response.status === 200){
router.reload()
router.push("/dashboard/artist/requests/"+params.row["id"])
}
else{
alert("Error accepting request.")
@ -121,98 +107,7 @@ export default function ServerPaginationGrid() {
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}>
<Typography variant="h6" align="center">Reference Images</Typography>
</Grid>
<Grid item xs={12} md={12}>
<RequestReferences id={params.row.id} />
</Grid>
</Grid>
</CardContent>
</Card>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={6}>
<Grid container spacing={3}>
<Grid item xs={12} md={12}>
<Tooltip arrow title="Decline this request.">
<IconButton onClick={denyRequest} disabled={params.row.declined || params.row.accepted} color="error"><Close/></IconButton>
</Tooltip>
<Tooltip arrow title="Accept this request.">
<IconButton onClick={acceptRequest} disabled={params.row.declined || params.row.accepted} color="success"><Check/></IconButton>
</Tooltip>
<Tooltip arrow title="Upload asset image for customer.">
<IconButton disabled={!params.row.paid} color="primary"><Upload/></IconButton>
</Tooltip>
<Tooltip arrow 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="filled" 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 arrow 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={() => { router.push("/dashboard/artist/requests/"+params.row["id"])}} aria-label="accept" color="primary" ><OpenInNew/></IconButton></Tooltip>
{((params.row.accepted==false && params.row.declined==false && params.row.completed==false) ? (
<>
<Tooltip arrow title="Accept this request.">
@ -236,6 +131,129 @@ export default function ServerPaginationGrid() {
)
} }
];
}
else{
columns = [
{ field: 'id', headerName: 'ID', flex: 0.1, filterable: false, sortable: false},
{ field: 'status', headerName: 'Status', flex: 0.15, filterable: false, sortable: false, filterable: false,
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: 'message', headerName: 'Message', flex: 0.5, filterable: false, sortable: false,
renderCell: (params) => {
return <TextField size="small" fullWidth value={params.row.message} disabled />;
}},
{ field: 'amount', headerName: 'Amount', flex: 0.1, filterable: false, sortable: false, renderCell: (params) => {
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
}},
{ field: 'requestDate', headerName: 'Request Date', flex:0.15, filterable: false, sortable: false,
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, filterable: false, sortable: false,
renderCell: (params) =>{
const acceptRequest = async () => {
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/accept", { method: 'PUT' })
if(response.status === 200){
router.push("/dashboard/artist/requests/"+params.row["id"])
}
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.push("/dashboard/artist/requests/"+params.row["id"])
}
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.push("/dashboard/artist/requests/"+params.row["id"])
}
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 (<>
<Tooltip arrow title="View more details."><IconButton onClick={() => { router.push("/dashboard/artist/requests/"+params.row["id"])}} aria-label="accept" color="primary" ><OpenInNew/></IconButton></Tooltip>
{((params.row.accepted==false && params.row.declined==false && params.row.completed==false) ? (
<>
<Tooltip arrow title="Accept this request.">
<IconButton onClick={acceptRequest} aria-label="accept" color="success"><Check/></IconButton>
</Tooltip>
<Tooltip arrow 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 arrow 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({});

View File

@ -0,0 +1,311 @@
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, CardHeader, CircularProgress, 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 {ArrowBack, Check, Close, Download, OpenInFull, OpenInNew, Refresh, Star, Upload } from '@mui/icons-material';
import PriceCheckIcon from '@mui/icons-material/PriceCheck';
import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn';
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
import ShoppingCartCheckoutIcon from '@mui/icons-material/ShoppingCartCheckout';
import { IconButton } from '@mui/material';
import Tooltip from '@mui/material/Tooltip';
import { Card, CardContent } from '@mui/material';
import Rating from '@mui/material/Rating';
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material';
import { Grid } from '@mui/material';
import { useRouter } from 'next/router';
import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'
import { useState, useEffect } from 'react';
import { Alert } from '@mui/material';
import { ImageList } from '@mui/material';
import AssetImage from '../../../../components/dashboard/artist/AssetImage'
import ReferenceImage from '../../../../components/dashboard/artist/ReferenceImage'
import { UploadBoxOutline } from 'mdi-material-ui';
const ArtistRequestDetails = () => {
const [references, setReferences] = useState([]);
const [assets, setAssets] = useState([]);
const [request, setRequest] = useState(null);
const router = useRouter();
const getData = async () => {
if(router.query.requestId!=null){
const response = await fetch("/api/requests/"+router.query.requestId+"/details");
const data = await response.json();
setRequest(data);
setRating(data.requestRating)
setReview(data.reviewMessage)
const requestResponse = await fetch("/api/artist/requests/"+router.query.requestId+"/references");
const requestJson = await requestResponse.json();
setReferences(requestJson);
const assetResponse = await fetch("/api/artist/requests/"+router.query.requestId+"/assets");
const assetJson = await assetResponse.json();
setAssets(assetJson);
}
}
const acceptRequest = async () => {
let response = await fetch('/api/artist/requests/'+request["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/'+request["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/'+request["id"]+"/complete", { method: 'PUT' })
if(response.status === 200){
router.reload()
}
else{
alert("Error accepting request.")
}
}
const handleReferenceUpload = async (event) =>{
const file = event.target.files[0];
const formData = new FormData();
formData.append('newImage', file);
fetch('/api/artist/requests/'+router.query.requestId+"/newasset", {
method: 'POST',
body: formData // Don't set Content-Type, FormData will handle it
})
.then(response => response.json())
.then(data => {
getData();
})
.catch(error => {
console.error('Error uploading file:', error);
// Handle error appropriately
});
}
useEffect(() => {
getData()
}, [router.query.requestId]);
const [open, setOpen] = React.useState(false);
const [rating, setRating] = React.useState(1);
const [review, setReview] = React.useState("");
const handlePay = async () => {
var paymentUrlRequest = await fetch('/api/requests/'+request.id+'/payment')
//console.log(paymentUrlRequest);
var paymentUrlJson = await paymentUrlRequest.json();
var paymentUrl = paymentUrlJson.paymentUrl;
window.open(paymentUrl);
}
let formattedTime = ""
const date = new Date(request?.requestDate ?? "");
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
return (<>
{(request) ? (
<Card>
<CardContent>
<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={request.message}
disabled
/>
</Grid>
<Grid item xs={12} md={12}>
<Grid container>
<Grid item xs={12} md={12}>
<ImageList variant="masonry">
{(references.map((reference) => (
<ReferenceImage referenceId={reference.id} requestId={request.id}/>
)))}
</ImageList>
</Grid>
<Grid item xs={12} md={12}>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={6}>
<Grid container spacing={3}>
<Grid item xs={12} md={10}>
<Grid container >
<Grid item xs={12} md={6}>
<Tooltip arrow title="Decline this request.">
<IconButton onClick={denyRequest} disabled={request.declined || request.accepted} color="error"><Close/></IconButton>
</Tooltip>
<Tooltip arrow title="Accept this request.">
<IconButton onClick={acceptRequest} disabled={request.declined || request.accepted} color="success"><Check/></IconButton>
</Tooltip>
<label htmlFor="uploadInput">
<Tooltip arrow title="Upload asset image for customer.">
<IconButton disabled={request.completed && request.paid} component="span" color="info"><UploadBoxOutline/></IconButton>
</Tooltip>
</label>
<Tooltip arrow title="Complete this request.">
<IconButton onClick={completeRequest} disabled={!request.paid || request.completed} color="success"><AssignmentTurnedInIcon/></IconButton>
</Tooltip>
</Grid>
<Grid item xs={12} md={6}>
<Stack spacing={2} direction="row">
{(request.declined ? (
<Tooltip title="The request has been declined.">
<Chip icon={<AssignmentLateIcon />} label="Declined" variant="outlined" color="error" />
</Tooltip>
):null)}
{(!request.declined && !request.accepted && !request.paid && !request.completed ? (
<Tooltip title="The request is pending.">
<Chip icon={<Refresh />} label="Pending" variant="outlined" color="secondary" />
</Tooltip>
):null)}
{(request.accepted && !request.completed ? (
<Tooltip title="The request has been accepted.">
<Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="outlined" color="info" />
</Tooltip>
):null)}
{(request.paid && request.accepted ? (
<Tooltip title="The request has been paid for you are clear to work on the request!">
<Chip icon={<PriceCheckIcon />} label="Paid" variant="outlined" color="success" />
</Tooltip>
):null)}
{(request.paid==false && request.accepted ? (
<Tooltip title="The request has not been paid for.">
<Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="outlined" color="warning" />
</Tooltip>
):null)}
{(request.completed ? (
<Tooltip title="The request has been completed.">
<Chip disabled={!request.completed} icon={<Check />} label="Completed" variant="outlined" color="success" />
</Tooltip>
):null)}
</Stack>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={2} sx={{textAlign:"right"}}>
<Tooltip title="Go back to viewing all your requests.">
<IconButton onClick={() => {router.push("/dashboard/artist/requests")}} color="primary">
<ArrowBack/>
</IconButton>
</Tooltip>
</Grid>
<Grid item xs={12} md={12}>
<Grid container>
<Grid item xs={12} md={12}>
<Alert icon={<Check />} severity="info">
Request submitted on {formattedTime}
</Alert>
</Grid>
<Grid item xs={12} md={12}>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={12}>
<Grid container spacing={3}>
<Grid item xs={12} md={12}>
{request.paid ? (
<>
<Grid container spacing={3}>
<Grid item xs={12} md={12}>
<Alert sx={{width:"100%"}} severity="success">The request has been paid for, start working on it!</Alert>
</Grid>
<Grid item xs={2} md={1}>
<input
id="uploadInput"
style={{ display: 'none' }}
accept="image/*"
type="file"
onChange={handleReferenceUpload}
disabled={request.completed}
/>
<label htmlFor="uploadInput">
<Tooltip arrow title="Upload a new reference image.">
{assets.length>0 ? (
<IconButton disabled={request.completed} component="span" color="info"><UploadBoxOutline sx={{fontSize:"2rem"}} /></IconButton>
):
(
<IconButton disabled={request.completed} component="span" color="warning"><UploadBoxOutline sx={{fontSize:"2rem"}} /></IconButton>
)}
</Tooltip>
</label>
</Grid>
<Grid item xs={10} md={11}>
{assets.length>0 ? (
<Alert sx={{width:"100%"}} severity="info">Your uploaded assets will appear below!</Alert>
):
(
<Alert sx={{width:"100%"}} severity="warning">You have not uploaded any assets!</Alert>
)}
</Grid>
<Grid item xs={12} md={12}>
</Grid>
</Grid>
</>
):(
<Alert sx={{width:"100%"}} severity="error">The request is not paid for do not work on the request!</Alert>
)}
</Grid>
<Grid item xs={12} md={12}>
<ImageList variant="masonry">
{(assets.map((asset) => (
<AssetImage assetId={asset.id} requestId={request.id}/>
)))}
</ImageList>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</CardContent>
</Card>
)
:(
<>
<Box sx={{paddingTop:"20%", textAlign:"center"}}>
<Typography variant="h6" component="h6" gutterBottom>
Loading...
</Typography>
<CircularProgress/>
</Box>
</>
)}
</>
);
};
// Protected route, checking user authentication client-side.(CSR)
export default withPageAuthRequired(ArtistRequestDetails);

View File

@ -18,19 +18,19 @@ import { withApiAuthRequired } from "@auth0/nextjs-auth0";
import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'
import Button from '@mui/material/Button'
import { CardContent } from '@mui/material'
import Onboarding from '../../components/Onboarding'
import Onboarding from '../../components/dashboard/Onboarding'
import { useState } from 'react'
import { useEffect } from 'react'
import router from 'next/router'
import { isObject } from 'util'
import Orders from '../../components/Orders'
import Orders from '../../components/dashboard/customer/orders'
import StatisticsCard from '../../views/dashboard/StatisticsCard'
import ArtistStats from '../../components/ArtistStats'
import { ArrowDownBox, BankTransfer, Cash, Clipboard, CubeOutline, StarOutline } from 'mdi-material-ui'
import CircularProgress from '@mui/material/CircularProgress'
import Tooltip from '@mui/material/Tooltip'
import Box from '@mui/material/Box'
import { Fullscreen, OpenInBrowser, Settings, WebAsset } from '@mui/icons-material'
import { Fullscreen, List, OpenInBrowser, Settings, WebAsset } from '@mui/icons-material'
@ -103,8 +103,8 @@ const Dashboard = () => {
<Grid item xs={12} md={4} sx={{textAlign:"center"}}>
</Grid>
<Grid item xs={12} md={5} sx={{textAlign:"right"}}>
<Tooltip title="Open an expanded view of your requests .">
<IconButton color="info" onClick={()=>{router.push("/dashboard/requests")}}><Fullscreen/></IconButton>
<Tooltip title="View all of your requests.">
<IconButton color="info" onClick={()=>{router.push("/dashboard/requests")}}><List/></IconButton>
</Tooltip>
</Grid>
<Grid item xs={12} md={12} sx={{paddingTop:"2%"}}>
@ -133,14 +133,14 @@ const Dashboard = () => {
)}
</Grid>
<Grid item xs={12} md={12}>
<Tooltip title="Open an expanded view of your reviews.">
<Tooltip title="View all 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.">
<Tooltip title="View all of your requests.">
<IconButton color="info" onClick={() => {router.push("/dashboard/artist/requests") }} size="large">
<CubeOutline style={{ fontSize: 64 }} />
<List style={{ fontSize: 64 }} />
</IconButton>
</Tooltip>
<Tooltip title="View your payouts and request related transactions.">

View File

@ -24,89 +24,46 @@ import { DownloadBox, StarOutline } from 'mdi-material-ui';
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material';
import { Grid } from '@mui/material';
import { useRouter } from 'next/router';
import { request } from 'http';
import { useMediaQuery } from '@mui/material';
export default function ServerPaginationGrid() {
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm')); // Check if the screen size is small
const router = useRouter();
const columns = [
{ field: 'id', headerName: 'ID', flex: 0.1},
{ field: 'status', headerName: 'Status', flex: 0.15,
let columns = [];
if(isSmallScreen){
columns = [
{ field: 'id', headerName: '', flex: 0.05, sortable: false, filterable: false},
{ field: 'status', headerName: 'Status', flex: 0.15, filterable: false, sortable: false,
renderCell: (params) => {
if(params.row.completed){
return <Chip icon={<Check />} label="Completed" variant="filled" color="success" />
return <Check color="success" />
}
else if(params.row.paid){
return <Chip icon={<PriceCheckIcon />} label="Paid" variant="filled" color="success" />
return <PriceCheckIcon color="success" />
}
else if(params.row.accepted && params.row.paid==false){
return <Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="filled" color="warning" />
return <PriceCheckIcon color="warning" />
}
else if(params.row.accepted && params.row.paid){
return <Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="filled" color="info" />
return <AssignmentTurnedInIcon color="info" />
}
else if(params.row.declined){
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="filled" color="error" />
return <AssignmentLateIcon color="error" />
}
else{
return <Chip icon={<Refresh />} label="Pending" variant="filled" color="secondary" />
return <Refresh 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) => {
{ field: 'amount', headerName: 'Amount', flex: 0.15, sortable: false, filterable: false, renderCell: (params) => {
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
}},
{ field: 'requestDate', headerName: 'Request Date', flex:0.15,
{ field: 'actions', headerName: '', flex:0.1, sortable: false, filterable: false,
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);
@ -114,174 +71,8 @@ export default function ServerPaginationGrid() {
var paymentUrl = paymentUrlJson.paymentUrl;
window.open(paymentUrl);
}
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 = () => {
setOpen(true);
};
const handleClose = () => {
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 = ""
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={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={<AssignmentLateIcon />} label="Declined" variant="filled" color="error" />
):null)}
</Grid>
<Grid item xs={12} md={12}>
{(params.row.accepted ? (
<Chip icon={<AssignmentTurnedInIcon />} 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={<PriceCheckIcon />} 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>
{(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}>
<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 arrow title="View more details."><IconButton onClick={handleClickOpen} aria-label="accept" color="primary"><OpenInNew/></IconButton></Tooltip>
<Tooltip arrow title="View more details."><IconButton onClick={() => { router.push("/dashboard/requests/"+params.row.id)}} aria-label="accept" color="primary"><OpenInNew/></IconButton></Tooltip>
{((params.row.accepted==true &&params.row.declined==false && params.row.paid==false) ? (
<Tooltip arrow title="Pay for this request."><IconButton onClick={handlePay} aria-label="accept" color="success"><ShoppingCartCheckoutIcon/></IconButton></Tooltip>
): null
@ -294,6 +85,78 @@ export default function ServerPaginationGrid() {
)
} }
];
}
else{
columns = [
{ field: 'id', headerName: 'ID', flex: 0.1, sortable: false, filterable: false},
{ field: 'status', headerName: 'Status', flex: 0.15, sortable: false, filterable: false,
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: 'message', headerName: 'Message', flex: 0.5, sortable: false, filterable: false,
renderCell: (params) => {
return <TextField size="small" fullWidth value={params.row.message} disabled />;
}},
{ field: 'amount', headerName: 'Amount', flex: 0.1, filterable: false, renderCell: (params) => {
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
}},
{ field: 'requestDate', headerName: 'Request Date', sortable: false, flex:0.15, filterable: false,
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: '', sortable: false, flex:0.1, filterable: false,
renderCell: (params) =>{
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);
}
return (<>
<Tooltip arrow title="View more details."><IconButton onClick={() => { router.push("/dashboard/requests/"+params.row.id)}} aria-label="accept" color="primary"><OpenInNew/></IconButton></Tooltip>
{((params.row.accepted==true &&params.row.declined==false && params.row.paid==false) ? (
<Tooltip arrow title="Pay for this request."><IconButton onClick={handlePay} aria-label="accept" color="success"><ShoppingCartCheckoutIcon/></IconButton></Tooltip>
): null
)}
{((params.row.completed) ? (
<Tooltip arrow 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({});

View File

@ -1,280 +1,327 @@
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 * 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 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);
}
import { Alert, Button, CircularProgress, ImageList, ImageListItem, ListItem, 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 {ArrowBack, AssignmentLateOutlined, Check, Close, Download, Error, OpenInFull, OpenInNew, Refresh, Star, Upload, Warning } from '@mui/icons-material';
import PriceCheckIcon from '@mui/icons-material/PriceCheck';
import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn';
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
import ShoppingCartCheckoutIcon from '@mui/icons-material/ShoppingCartCheckout';
import { IconButton } from '@mui/material';
import Tooltip from '@mui/material/Tooltip';
import { Card, CardContent } from '@mui/material';
import Rating from '@mui/material/Rating';
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material';
import { Grid } from '@mui/material';
import { useRouter } from 'next/router';
import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'
import { useState, useEffect } from 'react';
import { UploadBoxOutline } from 'mdi-material-ui';
import AssetImage from '../../../components/dashboard/artist/AssetImage'
import ReferenceImage from '../../../components/dashboard/artist/ReferenceImage'
import Paper from '@mui/material/Paper';
const RequestDetails = () => {
const [request, setRequest] = useState(null);
const [references, setReferences] = useState([]);
const [assets, setAssets] = useState([]);
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);
if(router.query.requestId!=null){
const response = await fetch("/api/requests/"+router.query.requestId+"/details");
const data = await response.json();
setRequest(data);
setRating(data.reviewRating)
setReview(data.reviewMessage)
setAlreadyReviewed(data.reviewed)
setDescription(sellerProfile["description"]);
setGuidelines(sellerProfile["requestGuidelines"]);
const requestResponse = await fetch("/api/requests/"+router.query.requestId+"/references");
const requestJson = await requestResponse.json();
setReferences(requestJson);
const assetsResponse = await fetch("/api/requests/"+router.query.requestId+"/assets");
const assetsJson = await assetsResponse.json();
setAssets(assetsJson);
}
}
const handleReferenceUpload = async (event) =>{
const file = event.target.files[0];
const formData = new FormData();
formData.append('newImage', file);
fetch('/api/requests/'+router.query.requestId+"/newreference", {
method: 'POST',
body: formData // Don't set Content-Type, FormData will handle it
})
.then(response => response.json())
.then(data => {
getData();
})
.catch(error => {
console.error('Error uploading file:', error);
// Handle error appropriately
});
}
useEffect(() => {
getData()
}, [router.query.artistName]);
}, [router.query.requestId]);
const columns: GridColDef[] = [
{
field: 'message',
headerName: 'Review',
flex: 0.75
const [open, setOpen] = React.useState(false);
const [rating, setRating] = React.useState(1);
const [review, setReview] = React.useState("");
const [alreadyReviewed, setAlreadyReviewed] = React.useState(true);
const handleReviewChange = (event) => {
setReview(event.target.value);
}
const handleRatingChange = async (event) => {
var rating = event.target.value;
var response = await fetch('/api/requests/'+request.id+'/review', {
method:"PUT",
headers: {
'Content-Type': 'application/json'
},
{
field: 'rating',
headerName: 'Rating',
flex: 0.25,
renderCell: (params: GridValueGetterParams) => (
<Rating name="read-only" value={params.value} readOnly />
),
},
];
body: JSON.stringify({
rating: rating,
message: review
})
});
if(response.ok){
router.reload();
}
else{
alert("Could not submit review!")
}
}
const handlePay = async () => {
var paymentUrlRequest = await fetch('/api/requests/'+request.id+'/payment')
//console.log(paymentUrlRequest);
var paymentUrlJson = await paymentUrlRequest.json();
var paymentUrl = paymentUrlJson.paymentUrl;
window.open(paymentUrl);
}
let formattedTime = ""
const date = new Date(request?.requestDate ?? "");
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
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 (<>
{(request) ? (
<Card>
<CardContent>
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 container spacing={3} sx={{paddingTop:"1%"}}>
<Grid item xs={12} md={6}>
<Grid container spacing={3}>
<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>
<Tooltip title="This is the message sent in with the request explaining what the customer wants.">
<TextField
multiline={true}
rows={10}
fullWidth
value={request.message}
disabled
/>
</Tooltip>
</Grid>
<Grid item xs={12} md={12} textAlign={"center"}>
<Card>
<CardContent>
<Grid item xs={12} md={12}>
<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 item xs={12} md={12}>
<Grid container>
<Grid item xs={12} md={12} >
<Typography variant="h5" align="center" gutterBottom>REVIEWS HEADER</Typography>
<Grid item xs={12} md={1}>
<input
id="uploadInput"
style={{ display: 'none' }}
accept="image/*"
type="file"
onChange={handleReferenceUpload}
disabled={request.declined || request.accepted}
/>
<label htmlFor="uploadInput">
<Tooltip arrow title="Upload a new reference image.">
<IconButton disabled={request.declined || request.accepted} component="span" color="info"><UploadBoxOutline sx={{fontSize:"2rem"}} /></IconButton>
</Tooltip>
</label>
</Grid>
<Grid item xs={12} md={12} >
<DataGrid
rows={rows}
columns={columns}
autoHeight={true}
initialState={{
pagination: {
paginationModel: {
pageSize: 5,
},
},
}}
pageSizeOptions={[5]}
<Grid item xs={12} md={11}>
{request.accepted ? (
<Alert sx={{width:"100%"}} severity="warning">You can no longer upload reference images, request is accepted!</Alert>
):(
(references.length > 0) ? (
<Alert severity="info">
There is a maximum of 10 reference images per request.
</Alert>
):(
<Alert sx={{width:"100%"}} severity="error">You need to add reference images to your request!</Alert>
)
)}
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={12}>
<ImageList variant="masonry">
{(references.map((reference) => (
<ReferenceImage referenceId={reference.id} requestId={request.id}/>
)))}
</ImageList>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={6}>
<Grid container spacing={3}>
<Grid item xs={12} md={10}>
<Grid container >
<Grid item xs={12} md={6}>
<Tooltip arrow title="Download all assets.">
<IconButton disabled={!request.completed} color="secondary"><Download/></IconButton>
</Tooltip>
<Tooltip arrow title="Pay for this request.">
<IconButton onClick={handlePay} disabled={!(request.accepted && !request.paid)} color="success"><ShoppingCartCheckoutIcon/></IconButton>
</Tooltip>
</Grid>
<Grid item xs={12} md={6}>
<Stack spacing={2} direction="row">
{(request.declined ? (
<Tooltip title="The request has been declined.">
<Chip icon={<AssignmentLateOutlined />} label="Declined" variant="outlined" color="error" />
</Tooltip>
):null)}
{(!request.declined && !request.accepted && !request.paid && !request.completed ? (
<Tooltip title="The request is pending.">
<Chip icon={<Refresh />} label="Pending" variant="outlined" color="secondary" />
</Tooltip>
):null)}
{(request.accepted && !request.completed ? (
<Tooltip title="The request has been accepted.">
<Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="outlined" color="info" />
</Tooltip>
):null)}
{(request.paid && request.accepted ? (
<Tooltip title="The request has been paid for and your request is being worked on.">
<Chip icon={<PriceCheckIcon />} label="Paid" variant="outlined" color="success" />
</Tooltip>
):null)}
{(request.paid==false && request.accepted ? (
<Tooltip title="You have not paid for this request.">
<Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="outlined" color="warning" />
</Tooltip>
):null)}
{(request.completed ? (
<Tooltip title="The request has been completed.">
<Chip disabled={!request.completed} icon={<Check />} label="Completed" variant="outlined" color="success" />
</Tooltip>
):null)}
</Stack>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={2} sx={{textAlign:"right"}}>
<Tooltip title="Go back to viewing all your requests.">
<IconButton onClick={() => {router.push("/dashboard/requests")}} color="primary">
<ArrowBack/>
</IconButton>
</Tooltip>
</Grid>
<Grid item xs={12} md={12}>
<Grid container>
<Grid item xs={12} md={12}>
<Alert icon={<Check />} severity="info">
Request submitted on {formattedTime}
</Alert>
</Grid>
<Grid item xs={12} md={12}>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={12}>
<Grid container spacing={3}>
<Grid item xs={12} md={12}>
{request.completed ? (
<Alert sx={{width:"100%"}} severity="success">Your success is complete and you can access your assets below!</Alert>
):(
<Alert sx={{width:"100%"}} severity="info">When your request is completed your assets will appear below!</Alert>
)}
</Grid>
{request.completed ? (
<Tooltip title={alreadyReviewed ? "You have already reviewed this request." : "Leave a review for this request now that it is completed!"}>
<Grid item xs={12} md={12}>
<Paper elevation={3} sx={{padding:"1%"}}>
<Grid container spacing={3}>
<Grid item xs={12} md={9}>
<TextField
fullWidth
focused
placeholder='Leave a review...'
value={review}
variant="outlined"
size="small"
disabled={alreadyReviewed}
onChange={handleReviewChange}
/>
</Grid>
<Grid item xs={12} md={3}>
<Rating
name="simple-controlled"
size="large"
value={rating}
disabled={!review || alreadyReviewed}
onChange={handleRatingChange}/>
</Grid>
<Grid item xs={12} md={12}>
{request.completed ? (
request.reviewed ? (
<Alert sx={{width:"100%"}} severity="info">You have reviewed this request so others know the quality of this artists work!</Alert>
):(
<Alert sx={{width:"100%"}} severity="warning">Please leave a review for this request so other users know the quality of this artists work!</Alert>
)
): null}
</Grid>
</Grid>
</Paper>
</Grid>
</Tooltip>
): null}
<Grid item xs={12} md={12}>
<ImageList variant="masonry">
{(assets.map((asset) => (
<AssetImage assetId={asset.id} requestId={request.id}/>
)))}
</ImageList>
</Grid>
</Grid>
</Grid>
</Grid>
</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}
)
:(
<>
<Box sx={{paddingTop:"20%", textAlign:"center"}}>
<Typography variant="h6" component="h6" gutterBottom>
Loading...
</Typography>
</Grid>
</Grid>
</CardContent>
</Card>
</Grid>
</Grid>
</CardContent>
</Card>
</Grid>
</Grid>
<CircularProgress/>
</Box>
</>
)}
</>
);
};
// Protected route, checking user authentication client-side.(CSR)
export default withPageAuthRequired(Profile);
export default withPageAuthRequired(RequestDetails);

View File

@ -1,37 +0,0 @@
// ** MUI Imports
import Grid from '@mui/material/Grid'
// ** Styled Component
import DatePickerWrapper from '../../core/styles/libs/react-datepicker'
// ** Demo Components Imports
import FormLayoutsBasic from '../../views/form-layouts/FormLayoutsBasic'
import FormLayoutsIcons from '../../views/form-layouts/FormLayoutsIcons'
import FormLayoutsSeparator from '../../views/form-layouts/FormLayoutsSeparator'
import FormLayoutsAlignment from '../../views/form-layouts/FormLayoutsAlignment'
// ** Third Party Styles Imports
import 'react-datepicker/dist/react-datepicker.css'
const FormLayouts = () => {
return (
<DatePickerWrapper>
<Grid container spacing={6}>
<Grid item xs={12} md={6}>
<FormLayoutsBasic />
</Grid>
<Grid item xs={12} md={6}>
<FormLayoutsIcons />
</Grid>
<Grid item xs={12}>
<FormLayoutsSeparator />
</Grid>
<Grid item xs={12}>
<FormLayoutsAlignment />
</Grid>
</Grid>
</DatePickerWrapper>
)
}
export default FormLayouts

View File

@ -1,164 +0,0 @@
// ** MUI Imports
import Grid from '@mui/material/Grid'
import Card from '@mui/material/Card'
import Link from '@mui/material/Link'
import Button from '@mui/material/Button'
import Tooltip from '@mui/material/Tooltip'
import Typography from '@mui/material/Typography'
import CardContent from '@mui/material/CardContent'
/**
** Icons Imports:
* ! You need to import all the icons which come from the API or from your server and then add these icons in 'icons' variable.
* ! If you need all the icons from the library, use "import * as Icon from 'mdi-material-ui'"
* */
import Abacus from 'mdi-material-ui/Abacus'
import Account from 'mdi-material-ui/Account'
import AbTesting from 'mdi-material-ui/AbTesting'
import AccountBox from 'mdi-material-ui/AccountBox'
import AccountCog from 'mdi-material-ui/AccountCog'
import AbjadArabic from 'mdi-material-ui/AbjadArabic'
import AbjadHebrew from 'mdi-material-ui/AbjadHebrew'
import AbugidaThai from 'mdi-material-ui/AbugidaThai'
import AccessPoint from 'mdi-material-ui/AccessPoint'
import AccountCash from 'mdi-material-ui/AccountCash'
import AccountEdit from 'mdi-material-ui/AccountEdit'
import AccountAlert from 'mdi-material-ui/AccountAlert'
import AccountCheck from 'mdi-material-ui/AccountCheck'
import AccountChild from 'mdi-material-ui/AccountChild'
import AccountClock from 'mdi-material-ui/AccountClock'
import AccountGroup from 'mdi-material-ui/AccountGroup'
import AccountCancel from 'mdi-material-ui/AccountCancel'
import AccountCircle from 'mdi-material-ui/AccountCircle'
import AccessPointOff from 'mdi-material-ui/AccessPointOff'
import AccountConvert from 'mdi-material-ui/AccountConvert'
import AccountDetails from 'mdi-material-ui/AccountDetails'
import AccessPointPlus from 'mdi-material-ui/AccessPointPlus'
import AccessPointCheck from 'mdi-material-ui/AccessPointCheck'
import AccessPointMinus from 'mdi-material-ui/AccessPointMinus'
import AccountArrowLeft from 'mdi-material-ui/AccountArrowLeft'
import AccountCowboyHat from 'mdi-material-ui/AccountCowboyHat'
import AbugidaDevanagari from 'mdi-material-ui/AbugidaDevanagari'
import AccessPointRemove from 'mdi-material-ui/AccessPointRemove'
import AccountArrowRight from 'mdi-material-ui/AccountArrowRight'
import AccountBoxOutline from 'mdi-material-ui/AccountBoxOutline'
import AccountCogOutline from 'mdi-material-ui/AccountCogOutline'
import AccessPointNetwork from 'mdi-material-ui/AccessPointNetwork'
import AccountBoxMultiple from 'mdi-material-ui/AccountBoxMultiple'
import AccountCashOutline from 'mdi-material-ui/AccountCashOutline'
import AccountChildCircle from 'mdi-material-ui/AccountChildCircle'
import AccountEditOutline from 'mdi-material-ui/AccountEditOutline'
import AccountAlertOutline from 'mdi-material-ui/AccountAlertOutline'
import AccountCheckOutline from 'mdi-material-ui/AccountCheckOutline'
import AccountChildOutline from 'mdi-material-ui/AccountChildOutline'
import AccountClockOutline from 'mdi-material-ui/AccountClockOutline'
import AccountCancelOutline from 'mdi-material-ui/AccountCancelOutline'
import AccountCircleOutline from 'mdi-material-ui/AccountCircleOutline'
import AccessPointNetworkOff from 'mdi-material-ui/AccessPointNetworkOff'
import AccountConvertOutline from 'mdi-material-ui/AccountConvertOutline'
import AccountDetailsOutline from 'mdi-material-ui/AccountDetailsOutline'
import AccountArrowLeftOutline from 'mdi-material-ui/AccountArrowLeftOutline'
import AccountArrowRightOutline from 'mdi-material-ui/AccountArrowRightOutline'
import AccountBoxMultipleOutline from 'mdi-material-ui/AccountBoxMultipleOutline'
const icons = {
Abacus,
Account,
AbTesting,
AccountBox,
AccountCog,
AbjadArabic,
AbjadHebrew,
AbugidaThai,
AccessPoint,
AccountCash,
AccountEdit,
AccountAlert,
AccountCheck,
AccountChild,
AccountClock,
AccountGroup,
AccountCancel,
AccountCircle,
AccessPointOff,
AccountConvert,
AccountDetails,
AccessPointPlus,
AccessPointCheck,
AccessPointMinus,
AccountArrowLeft,
AccountCowboyHat,
AbugidaDevanagari,
AccessPointRemove,
AccountArrowRight,
AccountBoxOutline,
AccountCogOutline,
AccessPointNetwork,
AccountBoxMultiple,
AccountCashOutline,
AccountChildCircle,
AccountEditOutline,
AccountAlertOutline,
AccountCheckOutline,
AccountChildOutline,
AccountClockOutline,
AccountCancelOutline,
AccountCircleOutline,
AccessPointNetworkOff,
AccountConvertOutline,
AccountDetailsOutline,
AccountArrowLeftOutline,
AccountArrowRightOutline,
AccountBoxMultipleOutline
}
const Icons = () => {
const renderIconGrids = () => {
return Object.keys(icons).map(key => {
const IconTag = icons[key as keyof typeof icons]
return (
<Grid item key={key}>
<Tooltip arrow title={key} placement='top'>
<Card>
<CardContent sx={{ display: 'flex' }}>
<IconTag />
</CardContent>
</Card>
</Tooltip>
</Grid>
)
})
}
return (
<Grid container spacing={6}>
<Grid item xs={12}>
<Typography variant='h5'>
<Link href='https://materialdesignicons.com/' target='_blank'>
Material Design Icons
</Link>
</Typography>
<Typography variant='body2'>Material Design Icons from the Community</Typography>
</Grid>
<Grid item xs={12}>
<Grid container spacing={6}>
{renderIconGrids()}
</Grid>
</Grid>
<Grid item xs={12} sx={{ textAlign: 'center' }}>
<Button
target='_blank'
rel='noreferrer'
component={Link}
variant='contained'
href='https://materialdesignicons.com/'
>
View All Material Design Icons
</Button>
</Grid>
</Grid>
)
}
export default Icons

View File

@ -1,14 +0,0 @@
// ** React Imports
import { ReactNode } from 'react'
// ** Layout Import
import BlankLayout from '../core/layouts/BlankLayout'
// ** Component Import
import Error404 from '../pages/404'
const ErrorPage = () => <Error404 />
ErrorPage.getLayout = (page: ReactNode) => <BlankLayout>{page}</BlankLayout>
export default ErrorPage

View File

@ -1,257 +0,0 @@
// ** React Imports
import { ChangeEvent, MouseEvent, ReactNode, useState } from 'react'
// ** Next Imports
import Link from 'next/link'
import { useRouter } from 'next/router'
// ** MUI Components
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
import Divider from '@mui/material/Divider'
import Checkbox from '@mui/material/Checkbox'
import TextField from '@mui/material/TextField'
import InputLabel from '@mui/material/InputLabel'
import Typography from '@mui/material/Typography'
import IconButton from '@mui/material/IconButton'
import CardContent from '@mui/material/CardContent'
import FormControl from '@mui/material/FormControl'
import OutlinedInput from '@mui/material/OutlinedInput'
import { styled, useTheme } from '@mui/material/styles'
import MuiCard, { CardProps } from '@mui/material/Card'
import InputAdornment from '@mui/material/InputAdornment'
import MuiFormControlLabel, { FormControlLabelProps } from '@mui/material/FormControlLabel'
// ** Icons Imports
import Google from 'mdi-material-ui/Google'
import Github from 'mdi-material-ui/Github'
import Twitter from 'mdi-material-ui/Twitter'
import Facebook from 'mdi-material-ui/Facebook'
import EyeOutline from 'mdi-material-ui/EyeOutline'
import EyeOffOutline from 'mdi-material-ui/EyeOffOutline'
// ** Configs
import themeConfig from '../configs/themeConfig'
// ** Layout Import
import BlankLayout from '../core/layouts/BlankLayout'
// ** Demo Imports
import FooterIllustrationsV1 from '../views/pages/auth/FooterIllustration'
interface State {
password: string
showPassword: boolean
}
// ** Styled Components
const Card = styled(MuiCard)<CardProps>(({ theme }) => ({
[theme.breakpoints.up('sm')]: { width: '28rem' }
}))
const LinkStyled = styled('a')(({ theme }) => ({
fontSize: '0.875rem',
textDecoration: 'none',
color: theme.palette.primary.main
}))
const FormControlLabel = styled(MuiFormControlLabel)<FormControlLabelProps>(({ theme }) => ({
'& .MuiFormControlLabel-label': {
fontSize: '0.875rem',
color: theme.palette.text.secondary
}
}))
const LoginPage = () => {
// ** State
const [values, setValues] = useState<State>({
password: '',
showPassword: false
})
// ** Hook
const theme = useTheme()
const router = useRouter()
const handleChange = (prop: keyof State) => (event: ChangeEvent<HTMLInputElement>) => {
setValues({ ...values, [prop]: event.target.value })
}
const handleClickShowPassword = () => {
setValues({ ...values, showPassword: !values.showPassword })
}
const handleMouseDownPassword = (event: MouseEvent<HTMLButtonElement>) => {
event.preventDefault()
}
return (
<Box className='content-center'>
<Card sx={{ zIndex: 1 }}>
<CardContent sx={{ padding: theme => `${theme.spacing(12, 9, 7)} !important` }}>
<Box sx={{ mb: 8, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<svg
width={35}
height={29}
version='1.1'
viewBox='0 0 30 23'
xmlns='http://www.w3.org/2000/svg'
xmlnsXlink='http://www.w3.org/1999/xlink'
>
<g stroke='none' strokeWidth='1' fill='none' fillRule='evenodd'>
<g id='Artboard' transform='translate(-95.000000, -51.000000)'>
<g id='logo' transform='translate(95.000000, 50.000000)'>
<path
id='Combined-Shape'
fill={theme.palette.primary.main}
d='M30,21.3918362 C30,21.7535219 29.9019196,22.1084381 29.7162004,22.4188007 C29.1490236,23.366632 27.9208668,23.6752135 26.9730355,23.1080366 L26.9730355,23.1080366 L23.714971,21.1584295 C23.1114106,20.7972624 22.7419355,20.1455972 22.7419355,19.4422291 L22.7419355,19.4422291 L22.741,12.7425689 L15,17.1774194 L7.258,12.7425689 L7.25806452,19.4422291 C7.25806452,20.1455972 6.88858935,20.7972624 6.28502902,21.1584295 L3.0269645,23.1080366 C2.07913318,23.6752135 0.850976404,23.366632 0.283799571,22.4188007 C0.0980803893,22.1084381 2.0190442e-15,21.7535219 0,21.3918362 L0,3.58469444 L0.00548573643,3.43543209 L0.00548573643,3.43543209 L0,3.5715689 C3.0881846e-16,2.4669994 0.8954305,1.5715689 2,1.5715689 C2.36889529,1.5715689 2.73060353,1.67359571 3.04512412,1.86636639 L15,9.19354839 L26.9548759,1.86636639 C27.2693965,1.67359571 27.6311047,1.5715689 28,1.5715689 C29.1045695,1.5715689 30,2.4669994 30,3.5715689 L30,3.5715689 Z'
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='0 8.58870968 7.25806452 12.7505183 7.25806452 16.8305646'
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='0 8.58870968 7.25806452 12.6445567 7.25806452 15.1370162'
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='22.7419355 8.58870968 30 12.7417372 30 16.9537453'
transform='translate(26.370968, 12.771227) scale(-1, 1) translate(-26.370968, -12.771227) '
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='22.7419355 8.58870968 30 12.6409734 30 15.2601969'
transform='translate(26.370968, 11.924453) scale(-1, 1) translate(-26.370968, -11.924453) '
/>
<path
id='Rectangle'
fillOpacity='0.15'
fill={theme.palette.common.white}
d='M3.04512412,1.86636639 L15,9.19354839 L15,9.19354839 L15,17.1774194 L0,8.58649679 L0,3.5715689 C3.0881846e-16,2.4669994 0.8954305,1.5715689 2,1.5715689 C2.36889529,1.5715689 2.73060353,1.67359571 3.04512412,1.86636639 Z'
/>
<path
id='Rectangle'
fillOpacity='0.35'
fill={theme.palette.common.white}
transform='translate(22.500000, 8.588710) scale(-1, 1) translate(-22.500000, -8.588710) '
d='M18.0451241,1.86636639 L30,9.19354839 L30,9.19354839 L30,17.1774194 L15,8.58649679 L15,3.5715689 C15,2.4669994 15.8954305,1.5715689 17,1.5715689 C17.3688953,1.5715689 17.7306035,1.67359571 18.0451241,1.86636639 Z'
/>
</g>
</g>
</g>
</svg>
<Typography
variant='h6'
sx={{
ml: 3,
lineHeight: 1,
fontWeight: 600,
textTransform: 'uppercase',
fontSize: '1.5rem !important'
}}
>
{themeConfig.templateName}
</Typography>
</Box>
<Box sx={{ mb: 6 }}>
<Typography variant='h5' sx={{ fontWeight: 600, marginBottom: 1.5 }}>
Welcome to {themeConfig.templateName}! 👋🏻
</Typography>
<Typography variant='body2'>Please sign-in to your account and start the adventure</Typography>
</Box>
<form noValidate autoComplete='off' onSubmit={e => e.preventDefault()}>
<TextField autoFocus fullWidth id='email' label='Email' sx={{ marginBottom: 4 }} />
<FormControl fullWidth>
<InputLabel htmlFor='auth-login-password'>Password</InputLabel>
<OutlinedInput
label='Password'
value={values.password}
id='auth-login-password'
onChange={handleChange('password')}
type={values.showPassword ? 'text' : 'password'}
endAdornment={
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
aria-label='toggle password visibility'
>
{values.showPassword ? <EyeOutline /> : <EyeOffOutline />}
</IconButton>
</InputAdornment>
}
/>
</FormControl>
<Box
sx={{ mb: 4, display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'space-between' }}
>
<FormControlLabel control={<Checkbox />} label='Remember Me' />
<Link passHref href='/'>
<LinkStyled onClick={e => e.preventDefault()}>Forgot Password?</LinkStyled>
</Link>
</Box>
<Button
fullWidth
size='large'
variant='contained'
sx={{ marginBottom: 7 }}
onClick={() => router.push('/')}
>
Login
</Button>
<Box sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'center' }}>
<Typography variant='body2' sx={{ marginRight: 2 }}>
New on our platform?
</Typography>
<Typography variant='body2'>
<Link passHref href='/pages/register'>
<LinkStyled>Create an account</LinkStyled>
</Link>
</Typography>
</Box>
<Divider sx={{ my: 5 }}>or</Divider>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Link href='/' passHref>
<IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}>
<Facebook sx={{ color: '#497ce2' }} />
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}>
<Twitter sx={{ color: '#1da1f2' }} />
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}>
<Github
sx={{ color: theme => (theme.palette.mode === 'light' ? '#272727' : theme.palette.grey[300]) }}
/>
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}>
<Google sx={{ color: '#db4437' }} />
</IconButton>
</Link>
</Box>
</form>
</CardContent>
</Card>
<FooterIllustrationsV1 />
</Box>
)
}
LoginPage.getLayout = (page: ReactNode) => <BlankLayout>{page}</BlankLayout>
export default LoginPage

View File

@ -1,255 +0,0 @@
// ** React Imports
import { useState, Fragment, ChangeEvent, MouseEvent, ReactNode } from 'react'
// ** Next Imports
import Link from 'next/link'
// ** MUI Components
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
import Divider from '@mui/material/Divider'
import Checkbox from '@mui/material/Checkbox'
import TextField from '@mui/material/TextField'
import Typography from '@mui/material/Typography'
import InputLabel from '@mui/material/InputLabel'
import IconButton from '@mui/material/IconButton'
import CardContent from '@mui/material/CardContent'
import FormControl from '@mui/material/FormControl'
import OutlinedInput from '@mui/material/OutlinedInput'
import { styled, useTheme } from '@mui/material/styles'
import MuiCard, { CardProps } from '@mui/material/Card'
import InputAdornment from '@mui/material/InputAdornment'
import MuiFormControlLabel, { FormControlLabelProps } from '@mui/material/FormControlLabel'
// ** Icons Imports
import Google from 'mdi-material-ui/Google'
import Github from 'mdi-material-ui/Github'
import Twitter from 'mdi-material-ui/Twitter'
import Facebook from 'mdi-material-ui/Facebook'
import EyeOutline from 'mdi-material-ui/EyeOutline'
import EyeOffOutline from 'mdi-material-ui/EyeOffOutline'
// ** Configs
import themeConfig from '../configs/themeConfig'
// ** Layout Import
import BlankLayout from '../core/layouts/BlankLayout'
// ** Demo Imports
import FooterIllustrationsV1 from '../views/pages/auth/FooterIllustration'
interface State {
password: string
showPassword: boolean
}
// ** Styled Components
const Card = styled(MuiCard)<CardProps>(({ theme }) => ({
[theme.breakpoints.up('sm')]: { width: '28rem' }
}))
const LinkStyled = styled('a')(({ theme }) => ({
fontSize: '0.875rem',
textDecoration: 'none',
color: theme.palette.primary.main
}))
const FormControlLabel = styled(MuiFormControlLabel)<FormControlLabelProps>(({ theme }) => ({
marginTop: theme.spacing(1.5),
marginBottom: theme.spacing(4),
'& .MuiFormControlLabel-label': {
fontSize: '0.875rem',
color: theme.palette.text.secondary
}
}))
const RegisterPage = () => {
// ** States
const [values, setValues] = useState<State>({
password: '',
showPassword: false
})
// ** Hook
const theme = useTheme()
const handleChange = (prop: keyof State) => (event: ChangeEvent<HTMLInputElement>) => {
setValues({ ...values, [prop]: event.target.value })
}
const handleClickShowPassword = () => {
setValues({ ...values, showPassword: !values.showPassword })
}
const handleMouseDownPassword = (event: MouseEvent<HTMLButtonElement>) => {
event.preventDefault()
}
return (
<Box className='content-center'>
<Card sx={{ zIndex: 1 }}>
<CardContent sx={{ padding: theme => `${theme.spacing(12, 9, 7)} !important` }}>
<Box sx={{ mb: 8, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<svg
width={35}
height={29}
version='1.1'
viewBox='0 0 30 23'
xmlns='http://www.w3.org/2000/svg'
xmlnsXlink='http://www.w3.org/1999/xlink'
>
<g stroke='none' strokeWidth='1' fill='none' fillRule='evenodd'>
<g id='Artboard' transform='translate(-95.000000, -51.000000)'>
<g id='logo' transform='translate(95.000000, 50.000000)'>
<path
id='Combined-Shape'
fill={theme.palette.primary.main}
d='M30,21.3918362 C30,21.7535219 29.9019196,22.1084381 29.7162004,22.4188007 C29.1490236,23.366632 27.9208668,23.6752135 26.9730355,23.1080366 L26.9730355,23.1080366 L23.714971,21.1584295 C23.1114106,20.7972624 22.7419355,20.1455972 22.7419355,19.4422291 L22.7419355,19.4422291 L22.741,12.7425689 L15,17.1774194 L7.258,12.7425689 L7.25806452,19.4422291 C7.25806452,20.1455972 6.88858935,20.7972624 6.28502902,21.1584295 L3.0269645,23.1080366 C2.07913318,23.6752135 0.850976404,23.366632 0.283799571,22.4188007 C0.0980803893,22.1084381 2.0190442e-15,21.7535219 0,21.3918362 L0,3.58469444 L0.00548573643,3.43543209 L0.00548573643,3.43543209 L0,3.5715689 C3.0881846e-16,2.4669994 0.8954305,1.5715689 2,1.5715689 C2.36889529,1.5715689 2.73060353,1.67359571 3.04512412,1.86636639 L15,9.19354839 L26.9548759,1.86636639 C27.2693965,1.67359571 27.6311047,1.5715689 28,1.5715689 C29.1045695,1.5715689 30,2.4669994 30,3.5715689 L30,3.5715689 Z'
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='0 8.58870968 7.25806452 12.7505183 7.25806452 16.8305646'
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='0 8.58870968 7.25806452 12.6445567 7.25806452 15.1370162'
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='22.7419355 8.58870968 30 12.7417372 30 16.9537453'
transform='translate(26.370968, 12.771227) scale(-1, 1) translate(-26.370968, -12.771227) '
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='22.7419355 8.58870968 30 12.6409734 30 15.2601969'
transform='translate(26.370968, 11.924453) scale(-1, 1) translate(-26.370968, -11.924453) '
/>
<path
id='Rectangle'
fillOpacity='0.15'
fill={theme.palette.common.white}
d='M3.04512412,1.86636639 L15,9.19354839 L15,9.19354839 L15,17.1774194 L0,8.58649679 L0,3.5715689 C3.0881846e-16,2.4669994 0.8954305,1.5715689 2,1.5715689 C2.36889529,1.5715689 2.73060353,1.67359571 3.04512412,1.86636639 Z'
/>
<path
id='Rectangle'
fillOpacity='0.35'
fill={theme.palette.common.white}
transform='translate(22.500000, 8.588710) scale(-1, 1) translate(-22.500000, -8.588710) '
d='M18.0451241,1.86636639 L30,9.19354839 L30,9.19354839 L30,17.1774194 L15,8.58649679 L15,3.5715689 C15,2.4669994 15.8954305,1.5715689 17,1.5715689 C17.3688953,1.5715689 17.7306035,1.67359571 18.0451241,1.86636639 Z'
/>
</g>
</g>
</g>
</svg>
<Typography
variant='h6'
sx={{
ml: 3,
lineHeight: 1,
fontWeight: 600,
textTransform: 'uppercase',
fontSize: '1.5rem !important'
}}
>
{themeConfig.templateName}
</Typography>
</Box>
<Box sx={{ mb: 6 }}>
<Typography variant='h5' sx={{ fontWeight: 600, marginBottom: 1.5 }}>
Adventure starts here 🚀
</Typography>
<Typography variant='body2'>Make your app management easy and fun!</Typography>
</Box>
<form noValidate autoComplete='off' onSubmit={e => e.preventDefault()}>
<TextField autoFocus fullWidth id='username' label='Username' sx={{ marginBottom: 4 }} />
<TextField fullWidth type='email' label='Email' sx={{ marginBottom: 4 }} />
<FormControl fullWidth>
<InputLabel htmlFor='auth-register-password'>Password</InputLabel>
<OutlinedInput
label='Password'
value={values.password}
id='auth-register-password'
onChange={handleChange('password')}
type={values.showPassword ? 'text' : 'password'}
endAdornment={
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
aria-label='toggle password visibility'
>
{values.showPassword ? <EyeOutline fontSize='small' /> : <EyeOffOutline fontSize='small' />}
</IconButton>
</InputAdornment>
}
/>
</FormControl>
<FormControlLabel
control={<Checkbox />}
label={
<Fragment>
<span>I agree to </span>
<Link href='/' passHref>
<LinkStyled onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}>
privacy policy & terms
</LinkStyled>
</Link>
</Fragment>
}
/>
<Button fullWidth size='large' type='submit' variant='contained' sx={{ marginBottom: 7 }}>
Sign up
</Button>
<Box sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'center' }}>
<Typography variant='body2' sx={{ marginRight: 2 }}>
Already have an account?
</Typography>
<Typography variant='body2'>
<Link passHref href='/pages/login'>
<LinkStyled>Sign in instead</LinkStyled>
</Link>
</Typography>
</Box>
<Divider sx={{ my: 5 }}>or</Divider>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Link href='/' passHref>
<IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}>
<Facebook sx={{ color: '#497ce2' }} />
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}>
<Twitter sx={{ color: '#1da1f2' }} />
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}>
<Github
sx={{ color: theme => (theme.palette.mode === 'light' ? '#272727' : theme.palette.grey[300]) }}
/>
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={(e: MouseEvent<HTMLElement>) => e.preventDefault()}>
<Google sx={{ color: '#db4437' }} />
</IconButton>
</Link>
</Box>
</form>
</CardContent>
</Card>
<FooterIllustrationsV1 />
</Box>
)
}
RegisterPage.getLayout = (page: ReactNode) => <BlankLayout>{page}</BlankLayout>
export default RegisterPage

View File

@ -1,67 +0,0 @@
// ** MUI Imports
import Grid from '@mui/material/Grid'
import Link from '@mui/material/Link'
import Card from '@mui/material/Card'
import Typography from '@mui/material/Typography'
import CardHeader from '@mui/material/CardHeader'
// ** Demo Components Imports
import TableBasic from '../views/tables/TableBasic'
import TableDense from '../views/tables/TableDense'
import TableSpanning from '../views/tables/TableSpanning'
import TableCustomized from '../views/tables/TableCustomized'
import TableCollapsible from '../views/tables/TableCollapsible'
import TableStickyHeader from '../views/tables/TableStickyHeader'
const MUITable = () => {
return (
<Grid container spacing={6}>
<Grid item xs={12}>
<Typography variant='h5'>
<Link href='https://mui.com/components/tables/' target='_blank'>
MUI Tables
</Link>
</Typography>
<Typography variant='body2'>Tables display sets of data. They can be fully customized</Typography>
</Grid>
<Grid item xs={12}>
<Card>
<CardHeader title='Basic Table' titleTypographyProps={{ variant: 'h6' }} />
<TableBasic />
</Card>
</Grid>
<Grid item xs={12}>
<Card>
<CardHeader title='Dense Table' titleTypographyProps={{ variant: 'h6' }} />
<TableDense />
</Card>
</Grid>
<Grid item xs={12}>
<Card>
<CardHeader title='Sticky Header' titleTypographyProps={{ variant: 'h6' }} />
<TableStickyHeader />
</Card>
</Grid>
<Grid item xs={12}>
<Card>
<CardHeader title='Collapsible Table' titleTypographyProps={{ variant: 'h6' }} />
<TableCollapsible />
</Card>
</Grid>
<Grid item xs={12}>
<Card>
<CardHeader title='Spanning Table' titleTypographyProps={{ variant: 'h6' }} />
<TableSpanning />
</Card>
</Grid>
<Grid item xs={12}>
<Card>
<CardHeader title='Customized Table' titleTypographyProps={{ variant: 'h6' }} />
<TableCustomized />
</Card>
</Grid>
</Grid>
)
}
export default MUITable

View File

@ -1,21 +0,0 @@
// ** MUI Imports
import Grid from '@mui/material/Grid'
// ** Demo Components Imports
import TypographyTexts from '../views/typography/TypographyTexts'
import TypographyHeadings from '../views/typography/TypographyHeadings'
const TypographyPage = () => {
return (
<Grid container spacing={6}>
<Grid item xs={12}>
<TypographyHeadings />
</Grid>
<Grid item xs={12}>
<TypographyTexts />
</Grid>
</Grid>
)
}
export default TypographyPage