mirror of
				https://github.com/D4M13N-D3V/comissions-app-ui.git
				synced 2025-10-31 01:25:22 +00:00 
			
		
		
		
	feat: admin list pages and apis
This commit is contained in:
		
							parent
							
								
									ff465278ad
								
							
						
					
					
						commit
						5a2f43768d
					
				| @ -8,7 +8,7 @@ import ListIcon from '@mui/icons-material/List'; | |||||||
| // ** Type import
 | // ** Type import
 | ||||||
| import { VerticalNavItemsType } from '../../core/layouts/types' | import { VerticalNavItemsType } from '../../core/layouts/types' | ||||||
| import { BankTransfer, Cart, Clipboard, PageFirst, StarOutline } from 'mdi-material-ui' | 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' | import { useState, useEffect } from 'react' | ||||||
| 
 | 
 | ||||||
| const navigation = (): VerticalNavItemsType => { | const navigation = (): VerticalNavItemsType => { | ||||||
| @ -46,10 +46,20 @@ const navigation = (): VerticalNavItemsType => { | |||||||
|       sectionTitle: 'Admin' |       sectionTitle: 'Admin' | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       title: 'Artist Requests', |       title: 'Manage Artist Access', | ||||||
|       icon: Clipboard, |       icon: LockPerson, | ||||||
|       path: '/dashboard/admin/requests' |       path: '/dashboard/admin/requests' | ||||||
|     }, |     }, | ||||||
|  |     { | ||||||
|  |       title: 'Manage Users', | ||||||
|  |       icon: People, | ||||||
|  |       path: '/dashboard/admin/users' | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       title: 'Manage Artists', | ||||||
|  |       icon: PeopleOutline, | ||||||
|  |       path: '/dashboard/admin/artists' | ||||||
|  |     }, | ||||||
|     { |     { | ||||||
|       sectionTitle: 'General' |       sectionTitle: 'General' | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -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 |  | ||||||
| @ -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; |  | ||||||
| @ -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(); |  | ||||||
							
								
								
									
										18
									
								
								pages/api/admin/artists.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								pages/api/admin/artists.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(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); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
							
								
								
									
										18
									
								
								pages/api/admin/artists/[artistId].tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								pages/api/admin/artists/[artistId].tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(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/'+userId, { | ||||||
|  |     headers: { | ||||||
|  |       "Authorization": `Bearer ${accessToken}` | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  |   if(response.ok==false){ | ||||||
|  |     res.status(200).json({}) | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   let result = await response.json(); | ||||||
|  |   res.status(200).json(result); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
							
								
								
									
										19
									
								
								pages/api/admin/artists/[artistId]/suspend.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								pages/api/admin/artists/[artistId]/suspend.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(req, res) { | ||||||
|  |   const { accessToken } = await getAccessToken(req, res); | ||||||
|  |   const { userId } = req.query; | ||||||
|  |   const response = await fetch(process.env.NEXT_PUBLIC_API_URL+'/api/admin/AdminArtists/'+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); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
							
								
								
									
										19
									
								
								pages/api/admin/artists/[artistId]/terminate.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								pages/api/admin/artists/[artistId]/terminate.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(req, res) { | ||||||
|  |   const { accessToken } = await getAccessToken(req, res); | ||||||
|  |   const { 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); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
							
								
								
									
										19
									
								
								pages/api/admin/artists/[artistId]/unsuspend.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								pages/api/admin/artists/[artistId]/unsuspend.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(req, res) { | ||||||
|  |   const { accessToken } = await getAccessToken(req, res); | ||||||
|  |   const { 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); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
							
								
								
									
										16
									
								
								pages/api/admin/artists/count.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								pages/api/admin/artists/count.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(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); | ||||||
|  | }); | ||||||
| @ -2,7 +2,8 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a | |||||||
| 
 | 
 | ||||||
| export default withApiAuthRequired(async function onboardUrl(req, res) { | export default withApiAuthRequired(async function onboardUrl(req, res) { | ||||||
|   const { accessToken } = await getAccessToken(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: { |     headers: { | ||||||
|       "Authorization": `Bearer ${accessToken}` |       "Authorization": `Bearer ${accessToken}` | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										20
									
								
								pages/api/admin/requests/[requestId].tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								pages/api/admin/requests/[requestId].tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(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 | ||||||
|  |   }); | ||||||
|  |   if(response.ok==false){ | ||||||
|  |     res.status(200).json({}) | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   let result = await response.json(); | ||||||
|  |   res.status(200).json(result); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | // handles ACCEPT AND DENY
 | ||||||
							
								
								
									
										16
									
								
								pages/api/admin/requests/count.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								pages/api/admin/requests/count.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(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
									
								
							
							
						
						
									
										18
									
								
								pages/api/admin/users.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(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); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
							
								
								
									
										18
									
								
								pages/api/admin/users/[userId].tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								pages/api/admin/users/[userId].tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(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); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
| @ -3,9 +3,9 @@ import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-a | |||||||
| export default withApiAuthRequired(async function onboardUrl(req, res) { | export default withApiAuthRequired(async function onboardUrl(req, res) { | ||||||
|   const { accessToken } = await getAccessToken(req, res); |   const { accessToken } = await getAccessToken(req, res); | ||||||
|   const { userId } = req.query; |   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/AdminUsers/'+userId+"/Ban", { | ||||||
|     headers: { |     headers: { | ||||||
|       "Authorization": `Bearer ${accessToken}`, |       "Authorization": `Bearer ${accessToken}` | ||||||
|     }, |     }, | ||||||
|     method: req.method |     method: req.method | ||||||
|   }); |   }); | ||||||
							
								
								
									
										19
									
								
								pages/api/admin/users/[userId]/suspend.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								pages/api/admin/users/[userId]/suspend.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(req, res) { | ||||||
|  |   const { accessToken } = await getAccessToken(req, res); | ||||||
|  |   const { 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); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
							
								
								
									
										19
									
								
								pages/api/admin/users/[userId]/unban.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								pages/api/admin/users/[userId]/unban.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(req, res) { | ||||||
|  |   const { accessToken } = await getAccessToken(req, res); | ||||||
|  |   const { 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); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
							
								
								
									
										19
									
								
								pages/api/admin/users/[userId]/unsuspend.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								pages/api/admin/users/[userId]/unsuspend.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(req, res) { | ||||||
|  |   const { accessToken } = await getAccessToken(req, res); | ||||||
|  |   const { 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); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
							
								
								
									
										16
									
								
								pages/api/admin/users/count.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								pages/api/admin/users/count.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | import { getAccessToken, withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'; | ||||||
|  | 
 | ||||||
|  | export default withApiAuthRequired(async function onboardUrl(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); | ||||||
|  | }); | ||||||
| @ -7,7 +7,9 @@ export default withApiAuthRequired(async function onboardUrl(req, res) { | |||||||
|       "Authorization": `Bearer ${accessToken}` |       "Authorization": `Bearer ${accessToken}` | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
|    |   if(response.ok==false){ | ||||||
|  |     res.status(200).json({}) | ||||||
|  |   } | ||||||
|   let result = await response.json(); |   let result = await response.json(); | ||||||
|   res.status(200).json(result); |   res.status(200).json(result); | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -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 |  | ||||||
							
								
								
									
										151
									
								
								pages/dashboard/admin/artists.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								pages/dashboard/admin/artists.tsx
									
									
									
									
									
										Normal 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/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/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> | ||||||
|  |   ); | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								pages/dashboard/admin/artists/[artistId].tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								pages/dashboard/admin/artists/[artistId].tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | import * as React from 'react'; | ||||||
|  | import { useState, useEffect } from 'react'; | ||||||
|  | import { useRouter } from 'next/router'; | ||||||
|  | import { withPageAuthRequired } from '@auth0/nextjs-auth0/client' | ||||||
|  | 
 | ||||||
|  | const AdminArtist = () => { | ||||||
|  |     const router = useRouter(); | ||||||
|  | 
 | ||||||
|  |     const getData = async () => { | ||||||
|  |         if(router.query.artistId!=null){ | ||||||
|  |              | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |    | ||||||
|  | 
 | ||||||
|  |     useEffect(() => { | ||||||
|  |         getData() | ||||||
|  |     }, [router.query.artistId]); | ||||||
|  | 
 | ||||||
|  |     return (<> | ||||||
|  |     </> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Protected route, checking user authentication client-side.(CSR)
 | ||||||
|  | export default withPageAuthRequired(ArtistRequestDetails); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @ -1,50 +1,206 @@ | |||||||
| import { useUser,withPageAuthRequired } from "@auth0/nextjs-auth0/client"; | import * as React from 'react'; | ||||||
| import { Grid, Typography } from "@mui/material"; | import { DataGrid } from '@mui/x-data-grid'; | ||||||
| import Card from "@mui/material/Card"; | import { GridColDef } from '@mui/x-data-grid'; | ||||||
| import CardContent from "@mui/material/CardContent"; |  | ||||||
| import EditableArtistPortfolio from "../../../components/Old/editableArtistPortfolio"; |  | ||||||
| import { useEffect, useState } from "react"; |  | ||||||
| import TextField from '@mui/material/TextField'; | import TextField from '@mui/material/TextField'; | ||||||
| import Button from '@mui/material/Button'; | import { Button, Stack, Typography } from '@mui/material'; | ||||||
| import Switch from '@mui/material/Switch'; | import CurrencyTextField from '@lupus-ai/mui-currency-textfield'; | ||||||
| import Divider from '@mui/material/Divider'; | import { DateField } from '@mui/x-date-pickers/DateField'; | ||||||
| import ArtistRequest from "../../../components/dashboard/admin/artistRequest"; | 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(); | import dayjs from 'dayjs'; | ||||||
|   const [artistRequestData, setArtistRequestData] = useState(null); | import { DownloadBox, Magnify, StarOutline } from 'mdi-material-ui'; | ||||||
|   const getData = () => { | import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, FormControl, InputLabel, Box } from '@mui/material'; | ||||||
|     fetch('/api/admin/requests').then(response => response.json().then(data => setArtistRequestData(data))) | 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 ( | ||||||
|  |                         <> | ||||||
|  |                             <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> | ||||||
|  |                         </> | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  |             }} | ||||||
|  |         ]; | ||||||
|  |     } | ||||||
|  |     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{ | ||||||
|  |                      | ||||||
|  |                     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); | ||||||
|   } |   } | ||||||
|   useEffect(() => { |   const getRequestsCount = async () => { | ||||||
|       getData() |     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 ( |   return ( | ||||||
|     <Grid container spacing={2}> |  | ||||||
|         {(artistRequestData != null && Object.keys(artistRequestData).length>0) ? ( |  | ||||||
|             (artistRequestData.map((request) => { |  | ||||||
|      |      | ||||||
|                 let formattedTime = ""; |     <div style={{ height: '100%', width: '100%' }}> | ||||||
|                 if (artistRequestData) { |     <LocalizationProvider dateAdapter={AdapterDayjs}> | ||||||
|                     const date = new Date(request["requestDate"]); |       <DataGrid | ||||||
|                     formattedTime = date.toLocaleTimeString('en-US', {  |         rows={requestData} | ||||||
|                         month: 'long',  |         columns={columns} | ||||||
|                         day: '2-digit',  |         rowCount={rowCountState} | ||||||
|                         year: 'numeric',  |         loading={isLoading} | ||||||
|                         hour12: true,  |         pageSizeOptions={[15]} | ||||||
|                         hour: '2-digit',  |         paginationModel={paginationModel} | ||||||
|                         minute: '2-digit'  |         paginationMode="server" | ||||||
|                     }); // Example format  
 |         onPaginationModelChange={setPaginationModel} | ||||||
|   } |       /> | ||||||
|                 return ( |         </LocalizationProvider> | ||||||
|                     <ArtistRequest userid={request["userId"]} id={request["id"]} username={""} message={request["message"]} date={formattedTime}  reload={getData} /> |     </div> | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|             ))   |  | ||||||
|         ):(<Typography>No requests</Typography>)} |  | ||||||
|     </Grid> |  | ||||||
|   ); |   ); | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| // Protected route, checking user authentication client-side.(CSR)
 |  | ||||||
| export default withPageAuthRequired(ArtistRequests); |  | ||||||
							
								
								
									
										28
									
								
								pages/dashboard/admin/requests/[requestId].tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								pages/dashboard/admin/requests/[requestId].tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | import * as React from 'react'; | ||||||
|  | import { useState, useEffect } from 'react'; | ||||||
|  | import { useRouter } from 'next/router'; | ||||||
|  | import { withPageAuthRequired } from '@auth0/nextjs-auth0/client' | ||||||
|  | 
 | ||||||
|  | const AdminRequest = () => { | ||||||
|  |     const router = useRouter(); | ||||||
|  | 
 | ||||||
|  |     const getData = async () => { | ||||||
|  |         if(router.query.artistId!=null){ | ||||||
|  |              | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |    | ||||||
|  | 
 | ||||||
|  |     useEffect(() => { | ||||||
|  |         getData() | ||||||
|  |     }, [router.query.artistId]); | ||||||
|  | 
 | ||||||
|  |     return (<> | ||||||
|  |     </> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Protected route, checking user authentication client-side.(CSR)
 | ||||||
|  | export default withPageAuthRequired(AdminRequest); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										147
									
								
								pages/dashboard/admin/users.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								pages/dashboard/admin/users.tsx
									
									
									
									
									
										Normal 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: "requestCount", headerName: "# of Requests", flex: 0.1, sortable: false, filterable: false}, | ||||||
|  |             { field: "reviewCount", 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> | ||||||
|  |   ); | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								pages/dashboard/admin/users/[userId].tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								pages/dashboard/admin/users/[userId].tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | import * as React from 'react'; | ||||||
|  | import { useState, useEffect } from 'react'; | ||||||
|  | import { useRouter } from 'next/router'; | ||||||
|  | import { withPageAuthRequired } from '@auth0/nextjs-auth0/client' | ||||||
|  | 
 | ||||||
|  | const AdminUser = () => { | ||||||
|  |     const router = useRouter(); | ||||||
|  | 
 | ||||||
|  |     const getData = async () => { | ||||||
|  |         if(router.query.artistId!=null){ | ||||||
|  |              | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |    | ||||||
|  | 
 | ||||||
|  |     useEffect(() => { | ||||||
|  |         getData() | ||||||
|  |     }, [router.query.artistId]); | ||||||
|  | 
 | ||||||
|  |     return (<> | ||||||
|  |     </> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Protected route, checking user authentication client-side.(CSR)
 | ||||||
|  | export default withPageAuthRequired(AdminUser); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @ -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 |  | ||||||
| @ -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 |  | ||||||
| @ -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 |  | ||||||
| @ -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 |  | ||||||
| @ -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 |  | ||||||
| @ -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 |  | ||||||
| @ -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 |  | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Damien Ostler
						Damien Ostler