diff --git a/components/ArtistStats.tsx b/components/ArtistStats.tsx index 3c50742..ea4dde7 100644 --- a/components/ArtistStats.tsx +++ b/components/ArtistStats.tsx @@ -85,7 +85,7 @@ const ArtistStats = ({profileData, stats}) => { /> `${theme.spacing(3)} !important` }}> - + { - + { - + { - + { - const [sellerData, setArtistData] = useState([]); - useEffect(() => { - const getData = async () => { - const response = await fetch('/api/discovery/artist/'+artistId); - const data = await response.json(); - setArtistData(data); - } - getData(); - }, []); - - return ( - - - - - - - {sellerData["name"]} - - - {sellerData["averageRating"] ? `${sellerData["averageRating"]} Stars (${sellerData["reviewCount"]} Reviews)` : "No Reviews"} - - - {sellerData["biography"]} - - - - - - - - {user ? ( - - ) : ( - - - - - - )} - - - - - - - - - - ) -} -export default Artist \ No newline at end of file diff --git a/components/Old/header.tsx b/components/Old/header.tsx deleted file mode 100644 index 0415525..0000000 --- a/components/Old/header.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import * as React from 'react'; -import { useUser } from "@auth0/nextjs-auth0/client"; -import AppBar from '@mui/material/AppBar'; -import Box from '@mui/material/Box'; -import Toolbar from '@mui/material/Toolbar'; -import Typography from '@mui/material/Typography'; -import Menu from '@mui/material/Menu'; -import Container from '@mui/material/Container'; -import Button from '@mui/material/Button'; -import MenuItem from '@mui/material/MenuItem'; -import { Chip, Icon } from '@mui/material'; -import { - NovuProvider, - PopoverNotificationCenter, - NotificationBell, -} from '@novu/notification-center'; - - -type HeaderProps = { - user?: any; - loading: boolean; -}; - - -const settings = ['Artist Dashboard', 'Account', 'Dashboard', 'Logout']; - -function ResponsiveAppBar() { - const [anchorElNav, setAnchorElNav] = React.useState(null); - const [anchorElUser, setAnchorElUser] = React.useState(null); - - const handleOpenNavMenu = (event: React.MouseEvent) => { - setAnchorElNav(event.currentTarget); - }; - const handleOpenUserMenu = (event: React.MouseEvent) => { - setAnchorElUser(event.currentTarget); - }; - - const handleCloseNavMenu = () => { - setAnchorElNav(null); - }; - - const handleCloseUserMenu = () => { - setAnchorElUser(null); - }; - - const { user, isLoading } = useUser(); - - return ( - - - - - - REQUEST.BOX - - - - { - user ? ( - <> - - - - {({ unseenCount }) => } - - - - - - - - - - - - - - - - - - - - - - ) : ( - <> - - - - - )} - - - - - ); -} -export default ResponsiveAppBar; \ No newline at end of file diff --git a/components/Old/layout.tsx b/components/Old/layout.tsx deleted file mode 100644 index ca925ae..0000000 --- a/components/Old/layout.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import Head from "next/head"; -import Header from "../header"; - -type LayoutProps = { - user?: any; - loading?: boolean; - children: React.ReactNode; -}; - -const Layout = ({ user, loading = false, children }: LayoutProps) => { - return ( - <> - - comissions.app - - -
- -
-
{children}
-
- - - - - ); -}; - -export default Layout; diff --git a/components/Old/swipableView.tsx b/components/Old/swipableView.tsx deleted file mode 100644 index 622b55e..0000000 --- a/components/Old/swipableView.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { useEffect, useRef } from "react" - -export default function SwipeableViews( - { className = "", index, onChangeIndex, ...rootProps }: - { index: number, onChangeIndex: (index: number) => void } & React.HTMLProps -) { - const containerRef = useRef(null) - const scrollTimeout = useRef() - - useEffect(() => { - containerRef.current?.children[index]?.scrollIntoView({ behavior: "smooth" }) - }, [index]) - - return ( -
{ - if (scrollTimeout.current) clearTimeout(scrollTimeout.current) - scrollTimeout.current = window.setTimeout(() => { - const pageWidth = currentTarget.scrollWidth / currentTarget.children.length - onChangeIndex(Math.round(currentTarget.scrollLeft / pageWidth)) - }, 100) - }} - /> - ) -} \ No newline at end of file diff --git a/components/Orders.tsx b/components/Orders.tsx index ee71ef2..c8f601b 100644 --- a/components/Orders.tsx +++ b/components/Orders.tsx @@ -44,19 +44,8 @@ export default function ServerPaginationGrid() { { field: 'amount', headerName: 'Amount', flex: 0.1, renderCell: (params) => { return ; }}, - { field: 'requestDate', headerName: 'Request Date', flex:0.15, - renderCell: (params) =>{ - - let formattedTime = "" - const date = new Date(params.row.requestDate); - formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format - return - } } + { field: 'requestDate', headerName: 'Request Date', flex:0.15, type: 'date' , + valueGetter: (params) => { return new Date(params.row.requestDate); }} ]; const [isLoading, setIsLoading] = React.useState(true); const [requestCount, setRequestCount] = React.useState(null); diff --git a/components/RequestDialog.tsx b/components/RequestDialog.tsx new file mode 100644 index 0000000..8a2e620 --- /dev/null +++ b/components/RequestDialog.tsx @@ -0,0 +1,143 @@ +import * as React from 'react'; +import { DataGrid, GridToolbar } from '@mui/x-data-grid'; +import { GridColDef } from '@mui/x-data-grid'; +import { Button, Stack, Typography } from '@mui/material'; +import { Chip, IconButton, Tooltip } from '@mui/material'; +import { AssignmentLateOutlined, AssignmentTurnedInOutlined, Check, Download, PriceCheck, PriceCheckOutlined, Refresh, ShoppingCartCheckout } from '@mui/icons-material'; +import { Card, CardContent } from '@mui/material'; +import Rating from '@mui/material/Rating'; +import { Dialog, DialogTitle, DialogContent, DialogActions, Grid, TextField } from '@mui/material'; +import { useRouter } from 'next/router'; +import { useState, useEffect } from 'react'; + + +export default function RequestDialog() { + + + return ( + Request submitted on {formattedTime ?? ''} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {(!params.row.declined && !params.row.accepted && !params.row.paid && !params.row.completed ? ( + } label="Pending" variant="filled" color="secondary" /> + ):null)} + + + {(params.row.declined ? ( + } label="Declined" variant="filled" color="error" /> + ):null)} + + + {(params.row.accepted ? ( + } label="Accepted" variant="filled" color="info" /> + ):null)} + + + {(params.row.paid && params.row.acccepted ? ( + + ):null)} + + + {(params.row.paid==false && params.row.accepted ? ( + } label="Pending Payment" variant="filled" color="warning" /> + ):null)} + + + {(params.row.completed ? ( + } label="Completed" variant="filled" color="success" /> + ):null)} + + + + + + + + { + // setValue(newValue); + // }} + /> + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} \ No newline at end of file diff --git a/components/Old/artistDashboardRequest.tsx b/components/artistDashboardRequest.tsx similarity index 100% rename from components/Old/artistDashboardRequest.tsx rename to components/artistDashboardRequest.tsx diff --git a/components/Old/artistPortfolio.tsx b/components/artistPortfolio.tsx similarity index 100% rename from components/Old/artistPortfolio.tsx rename to components/artistPortfolio.tsx diff --git a/components/Old/artistPortfolioImage.tsx b/components/artistPortfolioImage.tsx similarity index 100% rename from components/Old/artistPortfolioImage.tsx rename to components/artistPortfolioImage.tsx diff --git a/components/Old/editableArtistPortfolio.tsx b/components/editableArtistPortfolio.tsx similarity index 81% rename from components/Old/editableArtistPortfolio.tsx rename to components/editableArtistPortfolio.tsx index 426258f..3e5072b 100644 --- a/components/Old/editableArtistPortfolio.tsx +++ b/components/editableArtistPortfolio.tsx @@ -1,9 +1,11 @@ import * as React from 'react'; -import { ImageList, Box, Button, CircularProgress, Slider } from '@mui/material'; +import { ImageList, Box, Button, CircularProgress, Slider, IconButton } from '@mui/material'; import { useEffect, useState } from "react"; import EditableArtistPortfolioImage from './editableArtistPortfolioImage'; import FileOpenIcon from '@mui/icons-material/FileOpen'; +import { Tooltip } from '@mui/material'; import { Grid } from '@mui/material'; +import { FileUpload } from '@mui/icons-material'; const EditableArtistPortfolio = ({ artistId }) => { const [portfolioData, setPortfolioData] = useState([]); const [columns, setColumns] = useState(2); @@ -51,7 +53,7 @@ const EditableArtistPortfolio = ({ artistId }) => { ( - + { onChange={handlePortfolioUploadImageChange} /> - + + { marks min={1} max={5}/> + + diff --git a/components/Old/editableArtistPortfolioImage.tsx b/components/editableArtistPortfolioImage.tsx similarity index 100% rename from components/Old/editableArtistPortfolioImage.tsx rename to components/editableArtistPortfolioImage.tsx diff --git a/components/requestDialog.tsx b/components/requestDialog.tsx deleted file mode 100644 index 3b931d8..0000000 --- a/components/requestDialog.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import * as React from 'react'; -import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; -import Dialog, { DialogProps } from '@mui/material/Dialog'; -import DialogActions from '@mui/material/DialogActions'; -import DialogContent from '@mui/material/DialogContent'; -import DialogContentText from '@mui/material/DialogContentText'; -import DialogTitle from '@mui/material/DialogTitle'; -import FormControl from '@mui/material/FormControl'; -import FormControlLabel from '@mui/material/FormControlLabel'; -import InputLabel from '@mui/material/InputLabel'; -import MenuItem from '@mui/material/MenuItem'; -import Select, { SelectChangeEvent } from '@mui/material/Select'; -import Switch from '@mui/material/Switch'; - -export default function RequestDialog() { - const [open, setOpen] = React.useState(false); - - const handleClickOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; - - return ( - - - Optional sizes - - - You can set my maximum width and whether to adapt or not. - - - - maxWidth - - - - - - - - - ); -} \ No newline at end of file diff --git a/components/requestReferences.tsx b/components/requestReferences.tsx new file mode 100644 index 0000000..f6fbc31 --- /dev/null +++ b/components/requestReferences.tsx @@ -0,0 +1,28 @@ +import * as React from 'react'; +import {useEffect } from "react"; +import { ImageList, ImageListItem } from '@mui/material'; + +export default function RequestReferences({id}) { + const [open, setOpen] = React.useState(false); + const [refrences, setReferences] = React.useState([]); + + const getData = async () => { + const response = await fetch('/api/requests/' + id + '/references'); + const references = await response.json(); + setReferences(references); + + } + + useEffect(() => { + getData(); + }, []); + + return ( + {refrences.map((item) => ( + + {item.title} + + ))} + + ); +} \ No newline at end of file diff --git a/components/reviews.tsx b/components/reviews.tsx new file mode 100644 index 0000000..41e6dc1 --- /dev/null +++ b/components/reviews.tsx @@ -0,0 +1,85 @@ +import * as React from 'react'; +import { DataGrid } from '@mui/x-data-grid'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { useRouter } from 'next/router'; +import { Rating } from '@mui/material'; +import dayjs from 'dayjs'; + +import CurrencyTextField from '@lupus-ai/mui-currency-textfield'; +import { DateField } from '@mui/x-date-pickers'; + +export default function Reviews({artistId}) { + const router = useRouter(); + const columns = [ + { field: 'requestId', headerName: 'Request ID', flex: 0.1}, + { field: 'message', headerName: 'Review Message', flex: 0.5}, + { field: 'rating', headerName: 'Rating', flex: 0.2, renderCell: (params) => { + return ; + }} + ]; + const [isLoading, setIsLoading] = React.useState(true); + const [reviewCount, setReviewCount] = React.useState(null); + const [reviewData, setReviewData] = React.useState({}); + const [paginationModel, setPaginationModel] = React.useState({ + page: 0, + pageSize: 15, + }); + + + const getReviews = async () => { + setIsLoading(true); + const response = await fetch('/api/discovery/artist/'+artistId+'/reviews', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + } + }); + const data = await response.json(); + setReviewData(data); + setIsLoading(false); + } + const getReviewsCount = async () => { + const response = await fetch('/api/discovery/artist/'+artistId+'/reviewscount', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + } + }); + const data = await response.json(); + setReviewCount(data); + setRowCountState((prevRowCountState) => + data !== undefined + ? data + : prevRowCountState, + ); + return data; + } + + // Some API clients return undefined while loading + // Following lines are here to prevent `rowCountState` from being undefined during the loading + const [rowCountState, setRowCountState] = React.useState(0); + React.useEffect(() => { + getReviews(); + getReviewsCount(); + }, [reviewCount, setRowCountState,paginationModel]); + + return ( + +
+ + row.requestId} + rows={reviewData} + columns={columns} + rowCount={rowCountState} + loading={isLoading} + pageSizeOptions={[15]} + paginationModel={paginationModel} + paginationMode="server" + onPaginationModelChange={setPaginationModel} + /> + +
+ ); +} \ No newline at end of file diff --git a/configs/themeConfig.tsx b/configs/themeConfig.tsx index 1d02c6b..df21de1 100644 --- a/configs/themeConfig.tsx +++ b/configs/themeConfig.tsx @@ -18,7 +18,7 @@ type ThemeConfig = { const themeConfig: ThemeConfig = { // ** Layout Configs templateName: 'Request.Box' /* App Name */, - mode: 'light' /* light | dark */, + mode: 'dark' /* light | dark */, contentWidth: 'boxed' /* full | boxed */, // ** Routing Configs diff --git a/core/layouts/components/vertical/appBar/index.tsx b/core/layouts/components/vertical/appBar/index.tsx index 5127b57..663738d 100644 --- a/core/layouts/components/vertical/appBar/index.tsx +++ b/core/layouts/components/vertical/appBar/index.tsx @@ -7,7 +7,7 @@ import MuiAppBar, { AppBarProps } from '@mui/material/AppBar' import MuiToolbar, { ToolbarProps } from '@mui/material/Toolbar' // ** Type Import -import { Settings } from '../core/context/settingsContext' +import { Settings } from '../../../../context/settingsContext' interface Props { hidden: boolean diff --git a/layouts/components/vertical/AppBarContent.tsx b/layouts/components/vertical/AppBarContent.tsx index 51862f2..9701380 100644 --- a/layouts/components/vertical/AppBarContent.tsx +++ b/layouts/components/vertical/AppBarContent.tsx @@ -65,7 +65,7 @@ const AppBarContent = (props: Props) => { {(profileData ? ( - + {({ unseenCount }) => } diff --git a/navigation/vertical/index.ts b/navigation/vertical/index.ts index 001a6e1..13fdbf0 100644 --- a/navigation/vertical/index.ts +++ b/navigation/vertical/index.ts @@ -7,8 +7,8 @@ import SettingsApplicationsIcon from '@mui/icons-material/SettingsApplications'; // ** Type import import { VerticalNavItemsType } from '../../core/layouts/types' -import { BankTransfer, Cart, Clipboard, PageFirst } from 'mdi-material-ui' -import { DocumentScanner, FileOpen, Settings } from '@mui/icons-material' +import { BankTransfer, Cart, Clipboard, PageFirst, StarOutline } from 'mdi-material-ui' +import { DocumentScanner, FileOpen, OpenInBrowser, Settings, WebAsset } from '@mui/icons-material' import { useState, useEffect } from 'react' const navigation = (): VerticalNavItemsType => { @@ -70,6 +70,11 @@ const navigation = (): VerticalNavItemsType => { { sectionTitle: 'Artist' }, + { + title: 'Request Reviews', + icon: StarOutline, + path: '/dashboard/artist/reviews' + }, { title: 'Incoming Requests', icon: CubeOutline, @@ -78,21 +83,21 @@ const navigation = (): VerticalNavItemsType => { { title: 'Payments/Payouts', icon: BankTransfer, - path: '/dashboard/payout' + path: '/dashboard/artist/payout' }, { - title: 'Shop Settings', - icon: SettingsApplicationsIcon, + title: 'Artist Settings', + icon: Settings, path: '/dashboard/artist/artistsettings' }, { title: 'Page Settings', - icon: DocumentScanner, + icon: WebAsset, path: '/dashboard/artist/pagesettings' }, { title: 'Your Page', - icon: FileOpen, + icon: OpenInBrowser, path: '/box/' + (userData ? userData["displayName"] : "") } ); diff --git a/pages/api/artist/reviews.tsx b/pages/api/artist/reviews.tsx new file mode 100644 index 0000000..6394a47 --- /dev/null +++ b/pages/api/artist/reviews.tsx @@ -0,0 +1,19 @@ +import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; + +export default withApiAuthRequired(async function onboardUrl(req, res) { + const { accessToken } = await getAccessToken(req, res); + const { completed, declined, accepted, paid, offset, pageSize } = req.body; + const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Artist/Reviews`; + const response = await fetch(apiUrl, { + headers: { + "Authorization": `Bearer ${accessToken}` + } + }); + if(response.ok==false){ + res.status(200).json({}) + return; + } + let result = await response.json(); + res.status(200).json(result); +}); + diff --git a/pages/api/artist/reviewscount.tsx b/pages/api/artist/reviewscount.tsx new file mode 100644 index 0000000..81a61b8 --- /dev/null +++ b/pages/api/artist/reviewscount.tsx @@ -0,0 +1,19 @@ +import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; + +export default withApiAuthRequired(async function onboardUrl(req, res) { + const { accessToken } = await getAccessToken(req, res); + const { completed, declined, accepted, paid, offset, pageSize } = req.body; + const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/Artist/Reviews/Count`; + const response = await fetch(apiUrl, { + headers: { + "Authorization": `Bearer ${accessToken}` + } + }); + if(response.ok==false){ + res.status(200).json({}) + return; + } + let result = await response.json(); + res.status(200).json(result); +}); + diff --git a/pages/api/discovery/artist/[sellerId]/reviews.tsx b/pages/api/discovery/artist/[sellerId]/reviews.tsx new file mode 100644 index 0000000..843af45 --- /dev/null +++ b/pages/api/discovery/artist/[sellerId]/reviews.tsx @@ -0,0 +1,13 @@ +export default async function handler(req, res ): Promise { + const { sellerId } = req.query; + var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}/Reviews`; + (url) + const response = await fetch(url); + if (!response.ok) { + throw new Error('Failed to fetch seller portfolio'); + } + var result = await response.json(); + (result) + res.status(200).json(result); +} + diff --git a/pages/api/discovery/artist/[sellerId]/reviewscount.tsx b/pages/api/discovery/artist/[sellerId]/reviewscount.tsx new file mode 100644 index 0000000..94d0fe7 --- /dev/null +++ b/pages/api/discovery/artist/[sellerId]/reviewscount.tsx @@ -0,0 +1,13 @@ +export default async function handler(req, res ): Promise { + const { sellerId } = req.query; + var url = process.env.NEXT_PUBLIC_API_URL+`/api/Discovery/Artists/${sellerId}/Reviews/Count`; + (url) + const response = await fetch(url); + if (!response.ok) { + throw new Error('Failed to fetch seller portfolio'); + } + var result = await response.json(); + (result) + res.status(200).json(result); +} + diff --git a/pages/api/requests/[requestId]/references.tsx b/pages/api/requests/[requestId]/references.tsx index b6fc74f..febf661 100644 --- a/pages/api/requests/[requestId]/references.tsx +++ b/pages/api/requests/[requestId]/references.tsx @@ -3,15 +3,30 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a export default withApiAuthRequired(async function products(req, res) { const { accessToken } = await getAccessToken(req, res); const requestId = req.query.requestId; - const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Reference', { - headers: { - "Authorization": `Bearer ${accessToken}`, - 'Content-Type': 'application/json' - }, - method: req.method, - body: req.body - }); - let result = await response.json(); - res.status(200).json(result); + if(req.method == 'GET'){ + const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Reference', { + headers: { + "Authorization": `Bearer ${accessToken}`, + 'Content-Type': 'application/json' + }, + method: req.method + }); + console.log(response) + let result = await response.json(); + res.status(200).json(result); + } + else{ + const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Reference', { + 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); + } }); diff --git a/pages/api/requests/[requestId]/review.tsx b/pages/api/requests/[requestId]/review.tsx new file mode 100644 index 0000000..7b2fe8b --- /dev/null +++ b/pages/api/requests/[requestId]/review.tsx @@ -0,0 +1,17 @@ +import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; + +export default withApiAuthRequired(async function products(req, res) { + const { accessToken } = await getAccessToken(req, res); + const requestId = req.query.requestId; + const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Review', { + headers: { + "Authorization": `Bearer ${accessToken}`, + 'Content-Type': 'application/json' + }, + method: 'PUT', + body: JSON.stringify(req.body) + }); + let result = await response.json(); + res.status(200).json(result); +}); + diff --git a/pages/dashboard/artist/artistsettings.tsx b/pages/dashboard/artist/artistsettings.tsx index a7a0b49..fba5f36 100644 --- a/pages/dashboard/artist/artistsettings.tsx +++ b/pages/dashboard/artist/artistsettings.tsx @@ -1,8 +1,8 @@ import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client"; -import { CircularProgress, Grid, Typography } from "@mui/material"; +import { CircularProgress, Grid, IconButton, Tooltip, Typography } from "@mui/material"; import Card from "@mui/material/Card"; import CardContent from "@mui/material/CardContent"; -import EditableArtistPortfolio from "../../../components/Old/editableArtistPortfolio"; +import EditableArtistPortfolio from "../../../components/editableArtistPortfolio"; import { useEffect, useState } from "react"; import TextField from '@mui/material/TextField'; import Button from '@mui/material/Button'; @@ -10,6 +10,7 @@ import Switch from '@mui/material/Switch'; import Divider from '@mui/material/Divider'; import ArtistRequest from "../../../components/ArtistRequest"; import Box from '@mui/material/Box'; +import { Save } from "@mui/icons-material"; const ArtistSettings = () => { const {user, isLoading} = useUser(); @@ -91,8 +92,10 @@ const saveChanges = async () => { General Settings - - + + + + diff --git a/pages/dashboard/artist/pagesettings.tsx b/pages/dashboard/artist/pagesettings.tsx index 907203c..bb19287 100644 --- a/pages/dashboard/artist/pagesettings.tsx +++ b/pages/dashboard/artist/pagesettings.tsx @@ -7,12 +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/Old/editableArtistPortfolio"; -import ArtistPortfolio from "../../../components/Old/artistPortfolio"; +import EditableArtistPortfolio from "../../../components/editableArtistPortfolio"; +import ArtistPortfolio from "../../../components/artistPortfolio"; import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid'; import Rating from '@mui/material/Rating'; import CircularProgress from '@mui/material/CircularProgress'; import Box from '@mui/material/Box'; +import Reviews from "../../../components/reviews"; const Profile = () => { @@ -132,19 +133,9 @@ const Profile = () => { REVIEWS HEADER - + {profileData!=null ? ( + + ):null} diff --git a/pages/dashboard/payout.tsx b/pages/dashboard/artist/payout.tsx similarity index 54% rename from pages/dashboard/payout.tsx rename to pages/dashboard/artist/payout.tsx index 8afb1e8..26b877c 100644 --- a/pages/dashboard/payout.tsx +++ b/pages/dashboard/artist/payout.tsx @@ -1,5 +1,5 @@ import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client"; -import { CardHeader, Grid, Typography } from "@mui/material"; +import { CardHeader, Grid, IconButton, Typography } from "@mui/material"; import Card from "@mui/material/Card"; import CardContent from "@mui/material/CardContent"; import { useEffect, useState } from "react"; @@ -7,6 +7,7 @@ import CurrencyTextField from '@lupus-ai/mui-currency-textfield'; import Button from '@mui/material/Button'; import { OpenInNew } from "@mui/icons-material"; import CircularProgress from '@mui/material/CircularProgress'; +import Tooltip from '@mui/material/Tooltip'; import Box from '@mui/material/Box'; const Payout = () => { @@ -33,21 +34,14 @@ const Payout = () => { - + }/> - - - - - - - - - + + - - + + diff --git a/pages/dashboard/artist/requests.tsx b/pages/dashboard/artist/requests.tsx index 7b722d3..6994949 100644 --- a/pages/dashboard/artist/requests.tsx +++ b/pages/dashboard/artist/requests.tsx @@ -21,9 +21,7 @@ import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn'; import AssignmentLateIcon from '@mui/icons-material/AssignmentLate'; import { Card, CardHeader } from '@mui/material'; import { Dialog, DialogActions, DialogContent, DialogTitle, Grid, Stack } from '@mui/material'; -import RequestReferenceImage from '../../../components/Old/requestReferencesImage'; -import RequestReferences from '../../../components/Old/requestReferences'; - +import RequestReferences from '../../../components/requestReferences'; export default function ServerPaginationGrid() { const router = useRouter(); @@ -149,8 +147,10 @@ export default function ServerPaginationGrid() { + Reference Images + @@ -161,16 +161,16 @@ export default function ServerPaginationGrid() { - + - + - + - + {(!params.row.declined && !params.row.accepted && !params.row.paid && !params.row.completed ? ( @@ -189,7 +189,7 @@ export default function ServerPaginationGrid() { } label="Pending Payment" variant="filled" color="warning" /> ):null)} {(params.row.completed ? ( - } label="Completed" variant="outlined" color="success" /> + } label="Completed" variant="filled" color="success" /> ):null)} @@ -212,13 +212,13 @@ export default function ServerPaginationGrid() { - + {((params.row.accepted==false && params.row.declined==false && params.row.completed==false) ? ( <> - + - + @@ -226,7 +226,7 @@ export default function ServerPaginationGrid() { )} {((params.row.accepted==true && params.row.declined==false && params.row.completed==false && params.row.paid==true) ? ( <> - + @@ -241,7 +241,7 @@ export default function ServerPaginationGrid() { const [requestData, setRequestData] = React.useState({}); const [paginationModel, setPaginationModel] = React.useState({ page: 0, - pageSize: 5, + pageSize: 15, }); @@ -311,7 +311,7 @@ export default function ServerPaginationGrid() { columns={columns} rowCount={rowCountState} loading={isLoading} - pageSizeOptions={[5]} + pageSizeOptions={[15]} paginationModel={paginationModel} paginationMode="server" onPaginationModelChange={handlePageChange} diff --git a/pages/dashboard/artist/reviews.tsx b/pages/dashboard/artist/reviews.tsx new file mode 100644 index 0000000..6eef0ce --- /dev/null +++ b/pages/dashboard/artist/reviews.tsx @@ -0,0 +1,97 @@ +import * as React from 'react'; +import { DataGrid } from '@mui/x-data-grid'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { useRouter } from 'next/router'; +import { Rating } from '@mui/material'; +import dayjs from 'dayjs'; + +import CurrencyTextField from '@lupus-ai/mui-currency-textfield'; +import { DateField } from '@mui/x-date-pickers'; + +export default function ServerPaginationGrid() { + const router = useRouter(); + const columns = [ + { field: 'requestId', headerName: 'Request ID', flex: 0.1}, + { field: 'message', headerName: 'Review Message', flex: 0.5}, + { field: 'rating', headerName: 'Rating', flex: 0.2, renderCell: (params) => { + return ; + }}, + { field: 'reviewDate', headerName: 'Reviewed On', flex: 0.2, renderCell: (params) => { + let formattedTime = "" + const date = new Date(params.row.reviewDate); + formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format + return + } + }, + ]; + const [isLoading, setIsLoading] = React.useState(true); + const [reviewCount, setReviewCount] = React.useState(null); + const [reviewData, setReviewData] = React.useState({}); + const [paginationModel, setPaginationModel] = React.useState({ + page: 0, + pageSize: 15, + }); + + + const getReviews = async () => { + setIsLoading(true); + const response = await fetch('/api/artist/reviews', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + } + }); + const data = await response.json(); + setReviewData(data); + setIsLoading(false); + } + const getReviewsCount = async () => { + const response = await fetch('/api/artist/reviewscount', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + } + }); + const data = await response.json(); + setReviewCount(data); + setRowCountState((prevRowCountState) => + data !== undefined + ? data + : prevRowCountState, + ); + return data; + } + + // Some API clients return undefined while loading + // Following lines are here to prevent `rowCountState` from being undefined during the loading + const [rowCountState, setRowCountState] = React.useState(0); + React.useEffect(() => { + getReviews(); + getReviewsCount(); + }, [reviewCount, setRowCountState,paginationModel]); + + return ( + +
+ + row.requestId} + rows={reviewData} + columns={columns} + rowCount={rowCountState} + loading={isLoading} + pageSizeOptions={[15]} + paginationModel={paginationModel} + paginationMode="server" + onPaginationModelChange={setPaginationModel} + /> + +
+ ); +} \ No newline at end of file diff --git a/pages/dashboard/index.tsx b/pages/dashboard/index.tsx index 91ac0aa..ddc52dc 100644 --- a/pages/dashboard/index.tsx +++ b/pages/dashboard/index.tsx @@ -13,7 +13,7 @@ import CardStatisticsVerticalComponent from '../../core/components/card-statisti // ** Styled Component Import import ApexChartWrapper from '../../core/styles/libs/react-apexcharts' -import { Card, TextField, Typography } from '@mui/material' +import { Card, IconButton, TextField, Typography } from '@mui/material' import { withApiAuthRequired } from "@auth0/nextjs-auth0"; import { withPageAuthRequired } from '@auth0/nextjs-auth0/client' import Button from '@mui/material/Button' @@ -26,13 +26,16 @@ import { isObject } from 'util' import Orders from '../../components/Orders' import StatisticsCard from '../../views/dashboard/StatisticsCard' import ArtistStats from '../../components/ArtistStats' -import { Clipboard } from 'mdi-material-ui' +import { ArrowDownBox, BankTransfer, Cash, Clipboard, CubeOutline, StarOutline } from 'mdi-material-ui' import CircularProgress from '@mui/material/CircularProgress' +import Tooltip from '@mui/material/Tooltip' import Box from '@mui/material/Box' +import { Fullscreen, OpenInBrowser, Settings, WebAsset } from '@mui/icons-material' const Dashboard = () => { + const [userData , setUserData] = useState(null) const [profileData, setArtistData] = useState(null); const [requestData, setArtistRequestData] = useState(null); const [onboardData, setOnboardedData] = useState(false); @@ -46,6 +49,9 @@ const Dashboard = () => { } const getData = async () => { + const userResponse = await fetch('/api/me'); + const user = await userResponse.json(); + setUserData(user); const profileResponse = await fetch('/api/artist/profile'); const sellerProfile = await profileResponse.json(); setArtistData(sellerProfile); @@ -96,8 +102,10 @@ const Dashboard = () => {
- - + + + {router.push("/dashboard/requests")}}> + @@ -124,27 +132,41 @@ const Dashboard = () => { null )} - - http://localhost:3000/box/"{(profileData["name"].replace(/\s+/g, '-') ?? "")} + + + {router.push("/dashboard/artist/reviews") }} size="large"> + + + + + {router.push("/dashboard/artist/requests") }} size="large"> + + + + + { router.push("/dashboard/artist/payout") }} size="large"> + + + - - - - - - - - - - - - - - - - - + + + { router.push("/dashboard/artist/artistsettings") }} size="large"> + + + + + { router.push("/dashboard/artist/pagesettings") }} size="large"> + + + + + { router.push("/box/"+userData["displayName"]) }} size="large"> + + + +
diff --git a/pages/dashboard/requests.tsx b/pages/dashboard/requests.tsx index dfa7fd0..88d3d1f 100644 --- a/pages/dashboard/requests.tsx +++ b/pages/dashboard/requests.tsx @@ -8,7 +8,7 @@ import { DateField } from '@mui/x-date-pickers/DateField'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import Chip from '@mui/material/Chip'; -import {Check, Close, Download, OpenInFull, OpenInNew, Refresh, Upload } from '@mui/icons-material'; +import {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'; @@ -16,12 +16,12 @@ import ShoppingCartCheckoutIcon from '@mui/icons-material/ShoppingCartCheckout'; import { IconButton } from '@mui/material'; import Tooltip from '@mui/material/Tooltip'; import { Card, CardContent } from '@mui/material'; +import Rating from '@mui/material/Rating'; import dayjs from 'dayjs'; -import { DownloadBox } from 'mdi-material-ui'; +import { DownloadBox, StarOutline } from 'mdi-material-ui'; import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material'; -import RequestDialog from '../../components/requestDialog'; import { Grid } from '@mui/material'; import { useRouter } from 'next/router'; @@ -115,7 +115,9 @@ export default function ServerPaginationGrid() { 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); }; @@ -123,6 +125,31 @@ export default function ServerPaginationGrid() { 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); @@ -166,35 +193,74 @@ export default function ServerPaginationGrid() {
- - - - - - - - - - - {(!params.row.declined && !params.row.accepted && !params.row.paid && !params.row.completed ? ( - } label="Pending" variant="filled" color="secondary" /> - ):null)} - {(params.row.declined ? ( - } label="Declined" variant="filled" color="error" /> - ):null)} - {(params.row.accepted ? ( - } label="Accepted" variant="filled" color="info" /> - ):null)} - {(params.row.paid && params.row.acccepted ? ( - - ):null)} - {(params.row.paid==false && params.row.accepted ? ( - } label="Pending Payment" variant="filled" color="warning" /> - ):null)} - {(params.row.completed ? ( - } label="Completed" variant="outlined" color="success" /> - ):null)} + + + + + + + + + + + + + + + + + + + + {(!params.row.declined && !params.row.accepted && !params.row.paid && !params.row.completed ? ( + } label="Pending" variant="filled" color="secondary" /> + ):null)} + + + {(params.row.declined ? ( + } label="Declined" variant="filled" color="error" /> + ):null)} + + + {(params.row.accepted ? ( + } label="Accepted" variant="filled" color="info" /> + ):null)} + + + {(params.row.paid && params.row.acccepted ? ( + + ):null)} + + + {(params.row.paid==false && params.row.accepted ? ( + } label="Pending Payment" variant="filled" color="warning" /> + ):null)} + + + {(params.row.completed ? ( + } label="Completed" variant="filled" color="success" /> + ):null)} + + + + + {(params.row.completed) ? ( + + + + + + + + + ):null} @@ -215,13 +281,13 @@ export default function ServerPaginationGrid() { - + {((params.row.accepted==true &¶ms.row.declined==false && params.row.paid==false) ? ( - + ): null )} {((params.row.completed) ? ( - + ): null )} @@ -233,7 +299,7 @@ export default function ServerPaginationGrid() { const [requestData, setRequestData] = React.useState({}); const [paginationModel, setPaginationModel] = React.useState({ page: 0, - pageSize: 5, + pageSize: 15, }); @@ -299,7 +365,7 @@ export default function ServerPaginationGrid() { columns={columns} rowCount={rowCountState} loading={isLoading} - pageSizeOptions={[5]} + pageSizeOptions={[15]} paginationModel={paginationModel} paginationMode="server" onPaginationModelChange={setPaginationModel} diff --git a/pages/dashboard/settings.tsx b/pages/dashboard/settings.tsx index 04955eb..c4af047 100644 --- a/pages/dashboard/settings.tsx +++ b/pages/dashboard/settings.tsx @@ -1,5 +1,5 @@ import { useUser, withPageAuthRequired } from "@auth0/nextjs-auth0/client"; -import { CircularProgress, Grid, Typography } from "@mui/material"; +import { CircularProgress, Grid, IconButton, Typography } from "@mui/material"; import { useEffect, useState } from "react"; import Card from "@mui/material/Card"; import CardContent from "@mui/material/CardContent"; @@ -7,6 +7,8 @@ import TextField from '@mui/material/TextField'; import Button from '@mui/material/Button'; import Box from '@mui/material/Box'; import * as React from 'react'; +import { Save } from "@mui/icons-material"; +import Tooltip from '@mui/material/Tooltip'; const ArtistSettings = () => { @@ -64,11 +66,9 @@ const ArtistSettings = () => { General Settings - {(saved) ? ( - - ):( - - )} + + +