mirror of
https://github.com/D4M13N-D3V/comissions-app-ui.git
synced 2025-03-13 07:45:07 +00:00
feat: refactoring + assets and reference images and reviews
This commit is contained in:
parent
d52018f7eb
commit
93d4518500
@ -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>
|
||||
);
|
||||
}
|
@ -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
|
@ -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';
|
||||
|
41
components/dashboard/artist/AssetImage.tsx
Normal file
41
components/dashboard/artist/AssetImage.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useState } from "react";
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
|
||||
const AssetImage = ({ assetId, requestId }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const url = "/api/artist/requests/"+requestId+"/assets/"+assetId
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={assetId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={url}
|
||||
src={url}
|
||||
alt={assetId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={url}
|
||||
alt={assetId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default AssetImage;
|
41
components/dashboard/artist/ReferenceImage.tsx
Normal file
41
components/dashboard/artist/ReferenceImage.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useState } from "react";
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
|
||||
const ReferenceImage = ({ referenceId, requestId }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const url = "/api/artist/requests/"+requestId+"/references/"+referenceId
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={referenceId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={url}
|
||||
src={url}
|
||||
alt={referenceId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={url}
|
||||
alt={referenceId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ReferenceImage;
|
@ -1,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>
|
59
components/dashboard/artist/editablePortfolioImage.tsx
Normal file
59
components/dashboard/artist/editablePortfolioImage.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
import * as React from 'react';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import { Dialog, DialogContent, ImageList,ImageListItem, ImageListItemBar } from '@mui/material';
|
||||
import { IconButton } from '@mui/material';
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const EditableArtistPortfolioImage = ({ artistId, itemId, reload }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false); // State for controlling the dialog
|
||||
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
const deleteButton = () => {
|
||||
setDeleting(true);
|
||||
fetch('/api/artist/portfolio/' + itemId + "/delete", {
|
||||
method: 'DELETE'
|
||||
}).then(response => {
|
||||
reload().then(data => {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={itemId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
alt={itemId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
<ImageListItemBar
|
||||
actionIcon={
|
||||
<IconButton onClick={deleteButton} color="error">
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
}>
|
||||
</ImageListItemBar>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
alt={itemId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditableArtistPortfolioImage;
|
@ -1,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)
|
41
components/dashboard/artist/portfolioImage.tsx
Normal file
41
components/dashboard/artist/portfolioImage.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useState } from "react";
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
|
||||
const ArtistPortfolioImage = ({ artistId, itemId }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={itemId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
alt={itemId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={process.env.NEXT_PUBLIC_API_URL + `/api/Discovery/Artists/${artistId}/Portfolio/${itemId}`}
|
||||
alt={itemId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ArtistPortfolioImage;
|
@ -12,8 +12,8 @@ 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 />;
|
||||
}}
|
@ -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
|
41
components/dashboard/customer/AssetImage.tsx
Normal file
41
components/dashboard/customer/AssetImage.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useState } from "react";
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
|
||||
const AssetImage = ({ assetId, requestId }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const url = "/api/requests/"+requestId+"/assets/"+assetId
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={assetId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={url}
|
||||
src={url}
|
||||
alt={assetId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={url}
|
||||
alt={assetId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default AssetImage;
|
41
components/dashboard/customer/ReferenceImage.tsx
Normal file
41
components/dashboard/customer/ReferenceImage.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import { useState } from "react";
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
|
||||
const ReferenceImage = ({ referenceId, requestId }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const url = "/api/requests/"+requestId+"/references/"+referenceId
|
||||
const handleImageLoaded = () => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ImageListItem key={referenceId} onClick={() => setOpenDialog(true)}>
|
||||
<img
|
||||
srcSet={url}
|
||||
src={url}
|
||||
alt={referenceId}
|
||||
loading="lazy"
|
||||
style={{ filter: loaded ? 'blur(0)' : 'blur(10px)', backgroundColor: 'grey', cursor: 'pointer' }}
|
||||
onLoad={handleImageLoaded}
|
||||
/>
|
||||
</ImageListItem>
|
||||
{/* Dialog for displaying full-screen image */}
|
||||
<Dialog open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogContent>
|
||||
<img
|
||||
src={url}
|
||||
alt={referenceId}
|
||||
style={{ width: '100%', height: 'auto' }}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ReferenceImage;
|
@ -12,11 +12,12 @@ 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 dayjs from 'dayjs';
|
||||
|
||||
|
||||
export default function ServerPaginationGrid() {
|
||||
export default function CustomerOrders() {
|
||||
const columns = [
|
||||
{ field: 'id', headerName: 'ID', flex: 0.1},
|
||||
{ field: 'status', headerName: 'Status', flex: 0.15,
|
@ -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
|
@ -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>
|
||||
);
|
||||
}
|
@ -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're finished</Typography>
|
||||
<Button onClick={handleReset} sx={{ mt: 1, mr: 1 }}>
|
||||
Reset
|
||||
</Button>
|
||||
</Paper>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
@ -4,7 +4,7 @@ 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'
|
||||
@ -37,6 +37,11 @@ const navigation = (): VerticalNavItemsType => {
|
||||
}, []);
|
||||
|
||||
var result = [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
icon: HomeOutline,
|
||||
path: '/dashboard'
|
||||
},
|
||||
{
|
||||
sectionTitle: 'Admin'
|
||||
},
|
||||
@ -48,11 +53,6 @@ const navigation = (): VerticalNavItemsType => {
|
||||
{
|
||||
sectionTitle: 'General'
|
||||
},
|
||||
{
|
||||
title: 'Dashboard',
|
||||
icon: HomeOutline,
|
||||
path: '/dashboard'
|
||||
},
|
||||
{
|
||||
title: 'Account Settings',
|
||||
icon: Settings,
|
||||
@ -60,7 +60,7 @@ const navigation = (): VerticalNavItemsType => {
|
||||
},
|
||||
{
|
||||
title: 'Your Requests',
|
||||
icon: Cart,
|
||||
icon: ListIcon,
|
||||
path: '/dashboard/requests'
|
||||
}
|
||||
];
|
||||
@ -77,7 +77,7 @@ const navigation = (): VerticalNavItemsType => {
|
||||
},
|
||||
{
|
||||
title: 'Incoming Requests',
|
||||
icon: CubeOutline,
|
||||
icon: ListIcon,
|
||||
path: '/dashboard/artist/requests'
|
||||
},
|
||||
{
|
||||
|
100
package-lock.json
generated
100
package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
22
pages/api/artist/requests/[requestId]/assets.tsx
Normal file
22
pages/api/artist/requests/[requestId]/assets.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
import { IncomingForm } from 'formidable';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
const file = await fs.readFile(path);
|
||||
return new Blob([file]);
|
||||
}
|
||||
export default withApiAuthRequired(async function 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+'/Assets', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
24
pages/api/artist/requests/[requestId]/assets/[assetId].tsx
Normal file
24
pages/api/artist/requests/[requestId]/assets/[assetId].tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import axios from 'axios';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export default withApiAuthRequired(async function references(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);
|
||||
});
|
16
pages/api/artist/requests/[requestId]/details.tsx
Normal file
16
pages/api/artist/requests/[requestId]/details.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function requestDetails(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'GET'
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
52
pages/api/artist/requests/[requestId]/newasset.tsx
Normal file
52
pages/api/artist/requests/[requestId]/newasset.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import { IncomingForm } from 'formidable'
|
||||
import fs from 'fs/promises';
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
const file = await fs.readFile(path);
|
||||
return new Blob([file]);
|
||||
}
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
|
||||
const form = new IncomingForm();
|
||||
const requestId = req.query.requestId;
|
||||
|
||||
form.parse(req, async (err, fields, files) => {
|
||||
if (err) {
|
||||
console.error('Error parsing form:', err);
|
||||
res.status(500).json({ error: 'Error parsing form' });
|
||||
return;
|
||||
}
|
||||
const file = files["newImage"]; // Assuming your file input field name is 'file'
|
||||
try {
|
||||
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Assets', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
"Content-Type": " application/octet-stream"
|
||||
},
|
||||
body: await createBlobFromFile(file[0].filepath) // Don't set Content-Type, FormData will handle it
|
||||
});
|
||||
|
||||
(response)
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.message || 'Failed to upload file');
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
res.status(200).json(responseData);
|
||||
} catch (error) {
|
||||
console.error('Error uploading file:', error);
|
||||
res.status(500).json({ error: 'Error uploading file' });
|
||||
}
|
||||
});
|
||||
});
|
22
pages/api/artist/requests/[requestId]/references.tsx
Normal file
22
pages/api/artist/requests/[requestId]/references.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
import { IncomingForm } from 'formidable';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
const file = await fs.readFile(path);
|
||||
return new Blob([file]);
|
||||
}
|
||||
export default withApiAuthRequired(async function products(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/References', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
@ -0,0 +1,24 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import axios from 'axios';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export default withApiAuthRequired(async function references(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);
|
||||
});
|
@ -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) {
|
||||
if (req.method === 'POST') {
|
||||
const url = process.env.NEXT_PUBLIC_API_URL + `/api/Requests/Request`;
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
|
||||
export default async function handler(req, res ): Promise<any> {
|
||||
const { artistName } = req.query;
|
||||
var url = process.env.NEXT_PUBLIC_API_URL+`/api/Requests/Request`;
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const response = await fetch(url,{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: req.body, // Pipe the incoming request directly to the outgoing request
|
||||
});
|
||||
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: req.body
|
||||
});
|
||||
//console.log(response)
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch seller');
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
res.status(response.status).json(errorData);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
console.error('Error occurred during fetch:', error);
|
||||
res.status(500).json({ error: 'An error occurred during the request' });
|
||||
}
|
||||
} else {
|
||||
res.status(405).json({ error: 'Method Not Allowed' });
|
||||
}
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
}
|
||||
}
|
||||
|
22
pages/api/requests/[requestId]/assets.tsx
Normal file
22
pages/api/requests/[requestId]/assets.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
import { IncomingForm } from 'formidable';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
const file = await fs.readFile(path);
|
||||
return new Blob([file]);
|
||||
}
|
||||
export default withApiAuthRequired(async function products(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Assets', {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: req.method
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
24
pages/api/requests/[requestId]/assets/[assetId].tsx
Normal file
24
pages/api/requests/[requestId]/assets/[assetId].tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import axios from 'axios';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export default withApiAuthRequired(async function references(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const assetId = req.query.assetId;
|
||||
const response = await axios({
|
||||
method: 'get',
|
||||
url: `${process.env.NEXT_PUBLIC_API_URL}/api/Requests/Customer/${requestId}/Assets/${assetId}`,
|
||||
responseType: 'stream',
|
||||
headers: {
|
||||
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
}
|
||||
})
|
||||
|
||||
res.setHeader('Content-Type', response.headers['content-type']);
|
||||
|
||||
// Pipe the response stream directly to the response of the Next.js API Route
|
||||
response.data.pipe(res);
|
||||
});
|
16
pages/api/requests/[requestId]/details.tsx
Normal file
16
pages/api/requests/[requestId]/details.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';
|
||||
|
||||
export default withApiAuthRequired(async function requestDetails(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
const requestId = req.query.requestId;
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'GET'
|
||||
});
|
||||
let result = await response.json();
|
||||
res.status(200).json(result);
|
||||
});
|
||||
|
52
pages/api/requests/[requestId]/newreference.tsx
Normal file
52
pages/api/requests/[requestId]/newreference.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import { IncomingForm } from 'formidable'
|
||||
import fs from 'fs/promises';
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
async function createBlobFromFile(path: string): Promise<Blob> {
|
||||
const file = await fs.readFile(path);
|
||||
return new Blob([file]);
|
||||
}
|
||||
|
||||
export default withApiAuthRequired(async function handler(req, res) {
|
||||
const { accessToken } = await getAccessToken(req, res);
|
||||
|
||||
const form = new IncomingForm();
|
||||
const requestId = req.query.requestId;
|
||||
|
||||
form.parse(req, async (err, fields, files) => {
|
||||
if (err) {
|
||||
console.error('Error parsing form:', err);
|
||||
res.status(500).json({ error: 'Error parsing form' });
|
||||
return;
|
||||
}
|
||||
const file = files["newImage"]; // Assuming your file input field name is 'file'
|
||||
try {
|
||||
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/References', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
"Content-Type": " application/octet-stream"
|
||||
},
|
||||
body: await createBlobFromFile(file[0].filepath) // Don't set Content-Type, FormData will handle it
|
||||
});
|
||||
|
||||
(response)
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.message || 'Failed to upload file');
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
res.status(200).json(responseData);
|
||||
} catch (error) {
|
||||
console.error('Error uploading file:', error);
|
||||
res.status(500).json({ error: 'Error uploading file' });
|
||||
}
|
||||
});
|
||||
});
|
@ -1,32 +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;
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
|
24
pages/api/requests/[requestId]/references/[referenceId].tsx
Normal file
24
pages/api/requests/[requestId]/references/[referenceId].tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0';
|
||||
import axios from 'axios';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export default withApiAuthRequired(async function references(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);
|
||||
});
|
@ -16,11 +16,12 @@ 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 = () => {
|
||||
|
||||
@ -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
|
||||
|
||||
const requestResponse = await fetch('/api/box/newRequest', {
|
||||
method: 'POST',
|
||||
body: formData // Pass FormData containing the file
|
||||
});
|
||||
|
||||
if(requestResponse.ok){
|
||||
router.push("/dashboard/requests")
|
||||
} else {
|
||||
alert("Error submitting request")
|
||||
try {
|
||||
const requestResponse = await fetch('/api/box/newRequest', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
artistId: profileData["id"],
|
||||
message: payload.get('Message'),
|
||||
amount: payload.get('Amount'),
|
||||
})
|
||||
});
|
||||
if (requestResponse.ok) {
|
||||
const requestResponseData = await requestResponse.json();
|
||||
router.push("/dashboard/requests/"+requestResponseData["id"]);
|
||||
} else {
|
||||
const errorData = await requestResponse.json();
|
||||
alert("Error submitting request: " + errorData.detail);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error submitting request:', error);
|
||||
alert("Error submitting request. Please try again later.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getData = async () => {
|
||||
if(router.query.artistName!=null){
|
||||
@ -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,39 +134,17 @@ const Profile = () => {
|
||||
value={requestMessage}
|
||||
/>
|
||||
<CurrencyTextField
|
||||
label="Price"
|
||||
label="Amount"
|
||||
variant="standard"
|
||||
currencySymbol="$"
|
||||
name="Amount"
|
||||
outputFormat="number"
|
||||
decimalCharacter="."
|
||||
digitGroupSeparator=","
|
||||
fullWidth
|
||||
onChange={handleRequestPriceChange}
|
||||
value={requestPrice}
|
||||
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>
|
||||
|
@ -8,7 +8,7 @@ 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";
|
||||
|
||||
const ArtistRequests = () => {
|
||||
const {user, isLoading} = useUser();
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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 = () => {
|
||||
|
||||
|
@ -30,22 +30,22 @@ export default function ServerPaginationGrid() {
|
||||
{ field: 'status', headerName: 'Status', flex: 0.15,
|
||||
renderCell: (params) => {
|
||||
if(params.row.completed){
|
||||
return <Chip icon={<Check />} label="Completed" variant="filled" color="success" />
|
||||
return <Chip icon={<Check />} label="Completed" variant="outlined" color="success" />
|
||||
}
|
||||
else if(params.row.paid){
|
||||
return <Chip icon={<PriceCheckIcon />} label="Paid" variant="filled" color="success" />
|
||||
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="filled" color="warning" />
|
||||
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="filled" color="info" />
|
||||
return <Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="outlined" color="info" />
|
||||
}
|
||||
else if(params.row.declined){
|
||||
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="filled" color="error" />
|
||||
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="outlined" color="error" />
|
||||
}
|
||||
else{
|
||||
return <Chip icon={<Refresh />} label="Pending" variant="filled" color="secondary" />
|
||||
return <Chip icon={<Refresh />} label="Pending" variant="outlined" color="secondary" />
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -75,7 +75,7 @@ export default function ServerPaginationGrid() {
|
||||
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 +89,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 +99,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 +121,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.">
|
||||
|
310
pages/dashboard/artist/requests/[requestId].tsx
Normal file
310
pages/dashboard/artist/requests/[requestId].tsx
Normal file
@ -0,0 +1,310 @@
|
||||
import * as React from 'react';
|
||||
import { DataGrid } from '@mui/x-data-grid';
|
||||
import { GridColDef } from '@mui/x-data-grid';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import { Button, 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} 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>
|
||||
)
|
||||
:(
|
||||
<>
|
||||
<Typography variant="h6" component="h6" gutterBottom>
|
||||
Loading...
|
||||
</Typography>
|
||||
<Box sx={{paddingTop:"20%"}}></Box>
|
||||
<CircularProgress/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// Protected route, checking user authentication client-side.(CSR)
|
||||
export default withPageAuthRequired(ArtistRequestDetails);
|
||||
|
||||
|
@ -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.">
|
||||
|
@ -24,6 +24,7 @@ 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';
|
||||
|
||||
|
||||
export default function ServerPaginationGrid() {
|
||||
@ -33,22 +34,22 @@ export default function ServerPaginationGrid() {
|
||||
{ field: 'status', headerName: 'Status', flex: 0.15,
|
||||
renderCell: (params) => {
|
||||
if(params.row.completed){
|
||||
return <Chip icon={<Check />} label="Completed" variant="filled" color="success" />
|
||||
return <Chip icon={<Check />} label="Completed" variant="outlined" color="success" />
|
||||
}
|
||||
else if(params.row.paid){
|
||||
return <Chip icon={<PriceCheckIcon />} label="Paid" variant="filled" color="success" />
|
||||
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="filled" color="warning" />
|
||||
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="filled" color="info" />
|
||||
return <Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="outlined" color="info" />
|
||||
}
|
||||
else if(params.row.declined){
|
||||
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="filled" color="error" />
|
||||
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="outlined" color="error" />
|
||||
}
|
||||
else{
|
||||
return <Chip icon={<Refresh />} label="Pending" variant="filled" color="secondary" />
|
||||
return <Chip icon={<Refresh />} label="Pending" variant="outlined" color="secondary" />
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -74,214 +75,16 @@ export default function ServerPaginationGrid() {
|
||||
} },
|
||||
{ field: 'download', headerName: '', flex:0.1,
|
||||
renderCell: (params) =>{
|
||||
const acceptRequest = async () => {
|
||||
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/accept", { method: 'PUT' })
|
||||
if(response.status === 200){
|
||||
router.reload()
|
||||
}
|
||||
else{
|
||||
alert("Error accepting request.")
|
||||
}
|
||||
}
|
||||
|
||||
const viewRequest = async () => {
|
||||
|
||||
}
|
||||
|
||||
const denyRequest = async () => {
|
||||
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/deny", { method: 'PUT' })
|
||||
if(response.status === 200){
|
||||
router.reload()
|
||||
}
|
||||
else{
|
||||
alert("Error accepting request.")
|
||||
}
|
||||
}
|
||||
|
||||
const completeRequest = async () => {
|
||||
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/complete", { method: 'PUT' })
|
||||
if(response.status === 200){
|
||||
router.reload()
|
||||
}
|
||||
else{
|
||||
alert("Error accepting request.")
|
||||
}
|
||||
}
|
||||
|
||||
const handlePay = async () => {
|
||||
var paymentUrlRequest = await fetch('/api/requests/'+params.row.id+'/payment')
|
||||
//console.log(paymentUrlRequest);
|
||||
var paymentUrlJson = await paymentUrlRequest.json();
|
||||
var paymentUrl = paymentUrlJson.paymentUrl;
|
||||
window.open(paymentUrl);
|
||||
}
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [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
|
||||
|
||||
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 (<>
|
||||
<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 &¶ms.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
|
||||
|
@ -1,280 +1,317 @@
|
||||
import { withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Card from '@mui/material/Card';
|
||||
import CardActions from '@mui/material/CardActions';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import CardMedia from '@mui/material/CardMedia';
|
||||
import Button from '@mui/material/Button';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { useEffect, useState } from "react";
|
||||
import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid';
|
||||
import Rating from '@mui/material/Rating';
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogContentText from '@mui/material/DialogContentText';
|
||||
import DialogActions from '@mui/material/DialogActions';
|
||||
import CurrencyTextField from '@lupus-ai/mui-currency-textfield';
|
||||
import * 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.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)
|
||||
|
||||
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 getData = async () => {
|
||||
if(router.query.artistName!=null){
|
||||
const profileResponse = await fetch('/api/discovery/artist/'+router.query.artistName);
|
||||
const sellerProfile = await profileResponse.json();
|
||||
setArtistData(sellerProfile);
|
||||
|
||||
const handleReferenceUpload = async (event) =>{
|
||||
const file = event.target.files[0];
|
||||
const formData = new FormData();
|
||||
formData.append('newImage', file);
|
||||
|
||||
setDescription(sellerProfile["description"]);
|
||||
setGuidelines(sellerProfile["requestGuidelines"]);
|
||||
}
|
||||
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
|
||||
},
|
||||
{
|
||||
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 },
|
||||
];
|
||||
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [rating, setRating] = React.useState(1);
|
||||
const [review, setReview] = React.useState("");
|
||||
const [alreadyReviewed, setAlreadyReviewed] = React.useState(true);
|
||||
|
||||
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>
|
||||
const handleReviewChange = (event) => {
|
||||
setReview(event.target.value);
|
||||
}
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Card>
|
||||
<CardMedia
|
||||
sx={{ height: "250px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
image="https://images.pexels.com/photos/255379/pexels-photo-255379.jpeg?cs=srgb&dl=pexels-miguel-%C3%A1-padri%C3%B1%C3%A1n-255379.jpg&fm=jpg"
|
||||
title="green iguana"
|
||||
>
|
||||
<Typography variant="h5" align="center" gutterBottom>STORE HEADER</Typography>
|
||||
</CardMedia>
|
||||
<CardContent>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={6} >
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h5" align="center" gutterBottom>BIOGRAPHY HEADER</Typography>
|
||||
<Typography variant="body2" align="center">
|
||||
{description}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} textAlign={"center"}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Typography variant="h5" align="center" gutterBottom>GUIDELINES HEADER</Typography>
|
||||
<Typography variant="body2" align="center">
|
||||
{guidelines}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Typography variant="caption" color={"error"} align="center" sx={{marginTop:"4%"}}>
|
||||
By clicking "Start New Request" you are agreeing to the terms above and to the terms of service.
|
||||
</Typography>
|
||||
<Typography variant="caption" color={"primary"} align="center" sx={{marginTop:"4%"}}>
|
||||
[TERMS OF SERVICE]
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Button onClick={handleClickOpen} size="large" variant="contained" color="primary" sx={{marginTop:"2%"}}>Start New Request</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Typography variant="h5" align="center" gutterBottom>REVIEWS HEADER</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
<DataGrid
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
autoHeight={true}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: {
|
||||
pageSize: 5,
|
||||
},
|
||||
},
|
||||
}}
|
||||
pageSizeOptions={[5]}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
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'
|
||||
},
|
||||
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
|
||||
|
||||
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}>
|
||||
<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={6} >
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Typography variant="h5" align="center" gutterBottom>PORTFOLIO HEADER</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Typography variant="body2" align="center">
|
||||
{profileData!=null ? (
|
||||
<ArtistPortfolio masonry={true} columns={3} artistId={profileData["id"]} />
|
||||
):null}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Grid container>
|
||||
<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={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>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</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>
|
||||
</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>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
:(
|
||||
<>
|
||||
<Typography variant="h6" component="h6" gutterBottom>
|
||||
Loading...
|
||||
</Typography>
|
||||
<Box sx={{paddingTop:"20%"}}></Box>
|
||||
<CircularProgress/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// Protected route, checking user authentication client-side.(CSR)
|
||||
export default withPageAuthRequired(Profile);
|
||||
export default withPageAuthRequired(RequestDetails);
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user