Compare commits

...

9 Commits
0.9.0 ... main

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

View File

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

View File

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

View File

@ -4,10 +4,6 @@ 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();
@ -36,9 +32,13 @@ export default function Reviews({artistId}) {
}
});
const data = await response.json();
setReviewData(data);
// Assuming your API returns an array under a key like 'reviews'
// Adjust this according to your actual API response structure
const rows = data.reviews || []; // If 'reviews' doesn't exist, default to an empty array
setReviewData(rows);
setIsLoading(false);
}
const getReviewsCount = async () => {
const response = await fetch('/api/discovery/artist/'+artistId+'/reviewscount', {
method: 'GET',

View File

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

0
components/test.tsx Normal file
View File

View File

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

View File

@ -8,16 +8,22 @@ import ListIcon from '@mui/icons-material/List';
// ** Type import
import { VerticalNavItemsType } from '../../core/layouts/types'
import { BankTransfer, Cart, Clipboard, PageFirst, StarOutline } from 'mdi-material-ui'
import { DocumentScanner, FileOpen, OpenInBrowser, Settings, WebAsset } from '@mui/icons-material'
import { DocumentScanner, FileOpen, LockPerson, OpenInBrowser, People, PeopleOutline, Settings, WebAsset } from '@mui/icons-material'
import { useState, useEffect } from 'react'
const navigation = (): VerticalNavItemsType => {
const [isStripeOnboarded, setIsStripeOnboarded] = useState(false);
const [profileData, setProfileData] = useState(null);
const [userData, setUserData] = useState(null);
const [isAdmin, setIsAdmin] = useState(false);
const getData = async () => {
const adminCheck = await fetch('/api/admin/check', { method: "GET" });
if (adminCheck.status === 200) {
setIsAdmin(true);
}
const onboardCheckRequest = await fetch('/api/artist/onboarded', { method: "GET" });
const onboardCheckResponse = await onboardCheckRequest.json();
setIsStripeOnboarded(onboardCheckResponse["onboarded"]);
@ -42,14 +48,6 @@ const navigation = (): VerticalNavItemsType => {
icon: HomeOutline,
path: '/dashboard'
},
{
sectionTitle: 'Admin'
},
{
title: 'Artist Requests',
icon: Clipboard,
path: '/dashboard/admin/requests'
},
{
sectionTitle: 'General'
},
@ -65,6 +63,29 @@ const navigation = (): VerticalNavItemsType => {
}
];
if (isAdmin) {
result.push(
{
sectionTitle: 'Admin'
},
{
title: 'Manage Artist Access',
icon: LockPerson,
path: '/dashboard/admin/requests'
},
{
title: 'Manage Users',
icon: People,
path: '/dashboard/admin/users'
},
{
title: 'Manage Artists',
icon: PeopleOutline,
path: '/dashboard/admin/artists'
},
);
}
if (isStripeOnboarded) {
result.push(
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@ 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) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Artist/'+requestId+'/Assets', {

View File

@ -3,7 +3,7 @@ import axios from 'axios';
import fs from 'fs';
import path from 'path';
export default withApiAuthRequired(async function references(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const assetId = req.query.assetId;

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@ import axios from 'axios';
import fs from 'fs';
import path from 'path';
export default withApiAuthRequired(async function references(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const referenceId = req.query.referenceId;

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@ 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) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/Assets', {

View File

@ -3,7 +3,7 @@ import axios from 'axios';
import fs from 'fs';
import path from 'path';
export default withApiAuthRequired(async function references(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const assetId = req.query.assetId;

View File

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

View File

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

View File

@ -6,7 +6,7 @@ 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) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/Requests/Customer/'+requestId+'/References', {

View File

@ -3,7 +3,7 @@ import axios from 'axios';
import fs from 'fs';
import path from 'path';
export default withApiAuthRequired(async function references(req, res) {
export default withApiAuthRequired(async function handler(req, res) {
const { accessToken } = await getAccessToken(req, res);
const requestId = req.query.requestId;
const referenceId = req.query.referenceId;

View File

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

View File

@ -23,7 +23,7 @@ import { profile } from "console";
import FileOpen from "@mui/icons-material/FileOpen";
import Reviews from "../../components/dashboard/artist/reviews";
const Profile = () => {
const ArtistBox = () => {
const [profileData, setArtistData] = useState(null);
const [description, setDescription] = useState("");
@ -252,6 +252,6 @@ const Profile = () => {
};
// Protected route, checking user authentication client-side.(CSR)
export default withPageAuthRequired(Profile);
export default withPageAuthRequired(ArtistBox);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,55 +21,41 @@ import AssignmentTurnedInIcon from '@mui/icons-material/AssignmentTurnedIn';
import AssignmentLateIcon from '@mui/icons-material/AssignmentLate';
import { Card, CardHeader } from '@mui/material';
import { Dialog, DialogActions, DialogContent, DialogTitle, Grid, Stack } from '@mui/material';
import RequestReferences from '../../../components/requestReferences';
import { useMediaQuery } from '@mui/material';
export default function ServerPaginationGrid() {
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm')); // Check if the screen size is small
const router = useRouter();
const columns = [
{ field: 'id', headerName: 'ID', flex: 0.1},
{ field: 'status', headerName: 'Status', flex: 0.15,
let columns = []
if(isSmallScreen){
columns = [
{ field: 'id', headerName: 'ID', flex: 0.1, filterable: false, sortable: false},
{ field: 'status', headerName: 'Status', flex: 0.15, filterable: false, sortable: false,
renderCell: (params) => {
if(params.row.completed){
return <Chip icon={<Check />} label="Completed" variant="outlined" color="success" />
return <Check color="success" />
}
else if(params.row.paid){
return <Chip icon={<PriceCheckIcon />} label="Paid" variant="outlined" color="success" />
return <PriceCheckIcon color="success" />
}
else if(params.row.accepted && params.row.paid==false){
return <Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="outlined" color="warning" />
return <PriceCheckIcon color="warning" />
}
else if(params.row.accepted && params.row.paid){
return <Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="outlined" color="info" />
return <AssignmentTurnedInIcon color="info" />
}
else if(params.row.declined){
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="outlined" color="error" />
return <AssignmentLateIcon color="error" />
}
else{
return <Chip icon={<Refresh />} label="Pending" variant="outlined" color="secondary" />
return <Refresh color="secondary" />
}
}
},
{ field: 'message', headerName: 'Message', flex: 0.5,
renderCell: (params) => {
return <TextField size="small" fullWidth value={params.row.message} disabled />;
}},
{ field: 'amount', headerName: 'Amount', flex: 0.1, renderCell: (params) => {
{ field: 'amount', headerName: 'Amount', flex: 0.15, filterable: false, sortable: false, renderCell: (params) => {
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
}},
{ field: 'requestDate', headerName: 'Request Date', flex:0.15,
renderCell: (params) =>{
let formattedTime = ""
const date = new Date(params.row.requestDate);
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
return <DateField
size='small'
disabled
defaultValue={dayjs(params.row.requestDate)}
format="LL"
/>
} },
{ field: 'action', headerName: '', flex:0.15,
{ field: 'action', headerName: '', flex:0.1, filterable: false, sortable: false,
renderCell: (params) =>{
const acceptRequest = async () => {
@ -145,6 +131,129 @@ export default function ServerPaginationGrid() {
)
} }
];
}
else{
columns = [
{ field: 'id', headerName: 'ID', flex: 0.1, filterable: false, sortable: false},
{ field: 'status', headerName: 'Status', flex: 0.15, filterable: false, sortable: false, filterable: false,
renderCell: (params) => {
if(params.row.completed){
return <Chip icon={<Check />} label="Completed" variant="outlined" color="success" />
}
else if(params.row.paid){
return <Chip icon={<PriceCheckIcon />} label="Paid" variant="outlined" color="success" />
}
else if(params.row.accepted && params.row.paid==false){
return <Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="outlined" color="warning" />
}
else if(params.row.accepted && params.row.paid){
return <Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="outlined" color="info" />
}
else if(params.row.declined){
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="outlined" color="error" />
}
else{
return <Chip icon={<Refresh />} label="Pending" variant="outlined" color="secondary" />
}
}
},
{ field: 'message', headerName: 'Message', flex: 0.5, filterable: false, sortable: false,
renderCell: (params) => {
return <TextField size="small" fullWidth value={params.row.message} disabled />;
}},
{ field: 'amount', headerName: 'Amount', flex: 0.1, filterable: false, sortable: false, renderCell: (params) => {
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
}},
{ field: 'requestDate', headerName: 'Request Date', flex:0.15, filterable: false, sortable: false,
renderCell: (params) =>{
let formattedTime = ""
const date = new Date(params.row.requestDate);
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
return <DateField
size='small'
disabled
defaultValue={dayjs(params.row.requestDate)}
format="LL"
/>
} },
{ field: 'action', headerName: '', flex:0.15, filterable: false, sortable: false,
renderCell: (params) =>{
const acceptRequest = async () => {
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/accept", { method: 'PUT' })
if(response.status === 200){
router.push("/dashboard/artist/requests/"+params.row["id"])
}
else{
alert("Error accepting request.")
}
}
const viewRequest = async () => {
}
const denyRequest = async () => {
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/deny", { method: 'PUT' })
if(response.status === 200){
router.push("/dashboard/artist/requests/"+params.row["id"])
}
else{
alert("Error accepting request.")
}
}
const completeRequest = async () => {
let response = await fetch('/api/artist/requests/'+params.row["id"]+"/complete", { method: 'PUT' })
if(response.status === 200){
router.push("/dashboard/artist/requests/"+params.row["id"])
}
else{
alert("Error accepting request.")
}
}
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
let formattedTime = ""
const date = new Date(params.row.requestDate);
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
return (<>
<Tooltip arrow title="View more details."><IconButton onClick={() => { router.push("/dashboard/artist/requests/"+params.row["id"])}} aria-label="accept" color="primary" ><OpenInNew/></IconButton></Tooltip>
{((params.row.accepted==false && params.row.declined==false && params.row.completed==false) ? (
<>
<Tooltip arrow title="Accept this request.">
<IconButton onClick={acceptRequest} aria-label="accept" color="success"><Check/></IconButton>
</Tooltip>
<Tooltip arrow title="Deny this request.">
<IconButton onClick={denyRequest} aria-label="deny" sx={{marginLeft:"2px"}} color="error"><Close/></IconButton>
</Tooltip>
</>
): null
)}
{((params.row.accepted==true && params.row.declined==false && params.row.completed==false && params.row.paid==true) ? (
<>
<Tooltip arrow title="Complete this request.">
<IconButton onClick={completeRequest} aria-label="complete" color="success"><ClipboardCheck/></IconButton>
</Tooltip>
</>
): null
)}
</>
)
} }
];
}
const [isLoading, setIsLoading] = React.useState(true);
const [requestCount, setRequestCount] = React.useState(null);
const [requestData, setRequestData] = React.useState({});

View File

@ -170,7 +170,7 @@ const ArtistRequestDetails = () => {
</Tooltip>
<label htmlFor="uploadInput">
<Tooltip arrow title="Upload asset image for customer.">
<IconButton disabled={request.completed} component="span" color="info"><UploadBoxOutline/></IconButton>
<IconButton disabled={request.completed && request.paid} component="span" color="info"><UploadBoxOutline/></IconButton>
</Tooltip>
</label>
<Tooltip arrow title="Complete this request.">
@ -293,11 +293,12 @@ const ArtistRequestDetails = () => {
)
:(
<>
<Box sx={{paddingTop:"20%", textAlign:"center"}}>
<Typography variant="h6" component="h6" gutterBottom>
Loading...
</Typography>
<Box sx={{paddingTop:"20%"}}></Box>
<CircularProgress/>
</Box>
</>
)}
</>

View File

@ -25,55 +25,43 @@ import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, F
import { Grid } from '@mui/material';
import { useRouter } from 'next/router';
import { request } from 'http';
import { useMediaQuery } from '@mui/material';
export default function ServerPaginationGrid() {
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm')); // Check if the screen size is small
const router = useRouter();
const columns = [
{ field: 'id', headerName: 'ID', flex: 0.1},
{ field: 'status', headerName: 'Status', flex: 0.15,
let columns = [];
if(isSmallScreen){
columns = [
{ field: 'id', headerName: '', flex: 0.05, sortable: false, filterable: false},
{ field: 'status', headerName: 'Status', flex: 0.15, filterable: false, sortable: false,
renderCell: (params) => {
if(params.row.completed){
return <Chip icon={<Check />} label="Completed" variant="outlined" color="success" />
return <Check color="success" />
}
else if(params.row.paid){
return <Chip icon={<PriceCheckIcon />} label="Paid" variant="outlined" color="success" />
return <PriceCheckIcon color="success" />
}
else if(params.row.accepted && params.row.paid==false){
return <Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="outlined" color="warning" />
return <PriceCheckIcon color="warning" />
}
else if(params.row.accepted && params.row.paid){
return <Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="outlined" color="info" />
return <AssignmentTurnedInIcon color="info" />
}
else if(params.row.declined){
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="outlined" color="error" />
return <AssignmentLateIcon color="error" />
}
else{
return <Chip icon={<Refresh />} label="Pending" variant="outlined" color="secondary" />
return <Refresh color="secondary" />
}
}
},
{ field: 'message', headerName: 'Message', flex: 0.5,
renderCell: (params) => {
return <TextField size="small" fullWidth value={params.row.message} disabled />;
}},
{ field: 'amount', headerName: 'Amount', flex: 0.1, renderCell: (params) => {
{ field: 'amount', headerName: 'Amount', flex: 0.15, sortable: false, filterable: false, renderCell: (params) => {
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
}},
{ field: 'requestDate', headerName: 'Request Date', flex:0.15,
renderCell: (params) =>{
let formattedTime = ""
const date = new Date(params.row.requestDate);
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
return <DateField
size='small'
disabled
defaultValue={dayjs(params.row.requestDate)}
format="LL"
/>
} },
{ field: 'download', headerName: '', flex:0.1,
{ field: 'actions', headerName: '', flex:0.1, sortable: false, filterable: false,
renderCell: (params) =>{
const handlePay = async () => {
@ -97,6 +85,78 @@ export default function ServerPaginationGrid() {
)
} }
];
}
else{
columns = [
{ field: 'id', headerName: 'ID', flex: 0.1, sortable: false, filterable: false},
{ field: 'status', headerName: 'Status', flex: 0.15, sortable: false, filterable: false,
renderCell: (params) => {
if(params.row.completed){
return <Chip icon={<Check />} label="Completed" variant="outlined" color="success" />
}
else if(params.row.paid){
return <Chip icon={<PriceCheckIcon />} label="Paid" variant="outlined" color="success" />
}
else if(params.row.accepted && params.row.paid==false){
return <Chip icon={<PriceCheckIcon />} label="Pending Payment" variant="outlined" color="warning" />
}
else if(params.row.accepted && params.row.paid){
return <Chip icon={<AssignmentTurnedInIcon />} label="Accepted" variant="outlined" color="info" />
}
else if(params.row.declined){
return <Chip icon={<AssignmentLateIcon />} label="Declined" variant="outlined" color="error" />
}
else{
return <Chip icon={<Refresh />} label="Pending" variant="outlined" color="secondary" />
}
}
},
{ field: 'message', headerName: 'Message', flex: 0.5, sortable: false, filterable: false,
renderCell: (params) => {
return <TextField size="small" fullWidth value={params.row.message} disabled />;
}},
{ field: 'amount', headerName: 'Amount', flex: 0.1, filterable: false, renderCell: (params) => {
return <CurrencyTextField size="small" fullWidth value={params.row.amount} currencySymbol="$" disabled />;
}},
{ field: 'requestDate', headerName: 'Request Date', sortable: false, flex:0.15, filterable: false,
renderCell: (params) =>{
let formattedTime = ""
const date = new Date(params.row.requestDate);
formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format
return <DateField
size='small'
disabled
defaultValue={dayjs(params.row.requestDate)}
format="LL"
/>
} },
{ field: 'download', headerName: '', sortable: false, flex:0.1, filterable: false,
renderCell: (params) =>{
const handlePay = async () => {
var paymentUrlRequest = await fetch('/api/requests/'+params.row.id+'/payment')
//console.log(paymentUrlRequest);
var paymentUrlJson = await paymentUrlRequest.json();
var paymentUrl = paymentUrlJson.paymentUrl;
window.open(paymentUrl);
}
return (<>
<Tooltip arrow title="View more details."><IconButton onClick={() => { router.push("/dashboard/requests/"+params.row.id)}} aria-label="accept" color="primary"><OpenInNew/></IconButton></Tooltip>
{((params.row.accepted==true &&params.row.declined==false && params.row.paid==false) ? (
<Tooltip arrow title="Pay for this request."><IconButton onClick={handlePay} aria-label="accept" color="success"><ShoppingCartCheckoutIcon/></IconButton></Tooltip>
): null
)}
{((params.row.completed) ? (
<Tooltip arrow title="Download requests assets."><IconButton aria-label="download" color="secondary"><Download/></IconButton></Tooltip>
): null
)}
</>
)
} }
];
}
const [isLoading, setIsLoading] = React.useState(true);
const [requestCount, setRequestCount] = React.useState(null);
const [requestData, setRequestData] = React.useState({});

View File

@ -278,6 +278,15 @@ const RequestDetails = () => {
disabled={!review || alreadyReviewed}
onChange={handleRatingChange}/>
</Grid>
<Grid item xs={12} md={12}>
{request.completed ? (
request.reviewed ? (
<Alert sx={{width:"100%"}} severity="info">You have reviewed this request so others know the quality of this artists work!</Alert>
):(
<Alert sx={{width:"100%"}} severity="warning">Please leave a review for this request so other users know the quality of this artists work!</Alert>
)
): null}
</Grid>
</Grid>
</Paper>
</Grid>
@ -300,11 +309,12 @@ const RequestDetails = () => {
)
:(
<>
<Box sx={{paddingTop:"20%", textAlign:"center"}}>
<Typography variant="h6" component="h6" gutterBottom>
Loading...
</Typography>
<Box sx={{paddingTop:"20%"}}></Box>
<CircularProgress/>
</Box>
</>
)}
</>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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