diff --git a/components/AppAppBar.tsx b/components/AppAppBar.tsx index 8c5ad96..a0ebf47 100644 --- a/components/AppAppBar.tsx +++ b/components/AppAppBar.tsx @@ -146,7 +146,7 @@ function AppAppBar({ user }: AppAppBarProps) { variant="contained" size="small" component="a" - href="/api/auth/login" + href="/dashboard" startIcon={} > Dashboard diff --git a/components/artist.tsx b/components/Old/artist.tsx similarity index 100% rename from components/artist.tsx rename to components/Old/artist.tsx diff --git a/components/Old/artistDashboardRequest.tsx b/components/Old/artistDashboardRequest.tsx new file mode 100644 index 0000000..532e80a --- /dev/null +++ b/components/Old/artistDashboardRequest.tsx @@ -0,0 +1,53 @@ +import * as React from 'react'; +import { useEffect, useState } from "react"; +import { Grid, Card, CardContent, Typography } from '@mui/material'; +import CircularProgress from '@mui/material/CircularProgress'; +import Box from '@mui/material/Box'; + + +const ArtistDashboardRequest = () => { + const [sellerRequestData, setSellerRequestData] = useState(null); + + const getData = async () => { + const response = await fetch('/api/artist/request'); + const sellerProfile = await response.json(); + setSellerRequestData(sellerProfile); + } + useEffect(() => { + getData(); + }, []); + + let formattedTime = "" + if (sellerRequestData) { + const date = new Date(sellerRequestData["requestDate"]); + formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format + } + + return ( + (sellerRequestData ? ( + + + + + Request Status + + {(sellerRequestData["accepted"] ? ( + Accepted + ) : ( + Pending + ))} + Request submitted on {formattedTime ?? ''} + + ) : ( + + + + Loading + + + + + )) + ) + } +export default ArtistDashboardRequest \ No newline at end of file diff --git a/components/artistPortfolio.tsx b/components/Old/artistPortfolio.tsx similarity index 72% rename from components/artistPortfolio.tsx rename to components/Old/artistPortfolio.tsx index 3d5c47e..fc29e1b 100644 --- a/components/artistPortfolio.tsx +++ b/components/Old/artistPortfolio.tsx @@ -3,7 +3,7 @@ import {ImageList, Box, Typography, CircularProgress} from '@mui/material'; import { useEffect, useState } from "react"; import ArtistPortfolioImage from './artistPortfolioImage'; -const ArtistPortfolio = ({artistId}) => { +const ArtistPortfolio = ({masonry,columns,artistId}) => { const [portfolioData, setPortfolioData] = useState([]); const [loading, setLoading] = useState(true); // State for loading indicator useEffect(() => { @@ -26,11 +26,19 @@ const ArtistPortfolio = ({artistId}) => { ) : ( - + (masonry) ? ( + {portfolioData.map((item) => ( ))} + ):( + + {portfolioData.map((item) => ( + + ))} + + ) ) ) } diff --git a/components/artistPortfolioImage.tsx b/components/Old/artistPortfolioImage.tsx similarity index 96% rename from components/artistPortfolioImage.tsx rename to components/Old/artistPortfolioImage.tsx index 55e6900..b7004b7 100644 --- a/components/artistPortfolioImage.tsx +++ b/components/Old/artistPortfolioImage.tsx @@ -14,7 +14,7 @@ const ArtistPortfolioImage = ({artistId,itemId}) => { }; return ( - + { const [portfolioData, setPortfolioData] = useState([]); const [loading, setLoading] = useState(true); // State for loading indicator diff --git a/components/editableArtistPortfolioImage.tsx b/components/Old/editableArtistPortfolioImage.tsx similarity index 100% rename from components/editableArtistPortfolioImage.tsx rename to components/Old/editableArtistPortfolioImage.tsx diff --git a/components/header.tsx b/components/Old/header.tsx similarity index 100% rename from components/header.tsx rename to components/Old/header.tsx diff --git a/components/layout.tsx b/components/Old/layout.tsx similarity index 96% rename from components/layout.tsx rename to components/Old/layout.tsx index 0ddff72..ca925ae 100644 --- a/components/layout.tsx +++ b/components/Old/layout.tsx @@ -1,5 +1,5 @@ import Head from "next/head"; -import Header from "./header"; +import Header from "../header"; type LayoutProps = { user?: any; diff --git a/components/swipableView.tsx b/components/Old/swipableView.tsx similarity index 100% rename from components/swipableView.tsx rename to components/Old/swipableView.tsx diff --git a/components/Onboarding.tsx b/components/Onboarding.tsx new file mode 100644 index 0000000..543bfcd --- /dev/null +++ b/components/Onboarding.tsx @@ -0,0 +1,218 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import Stepper from '@mui/material/Stepper'; +import Step from '@mui/material/Step'; +import StepLabel from '@mui/material/StepLabel'; +import StepContent from '@mui/material/StepContent'; +import Button from '@mui/material/Button'; +import Paper from '@mui/material/Paper'; +import Typography from '@mui/material/Typography'; +import Grid from '@mui/material/Grid' +import TextField from '@mui/material/TextField'; +import ArtistDashboardRequest from '../components/Old/artistDashboardRequest'; +import ArtistPortfolio from '../components/Old/artistPortfolio'; +import EditableArtistPortfolio from '../components/Old/editableArtistPortfolio'; +import { useEffect, useState } from "react"; + +import CurrencyTextField from '@lupus-ai/mui-currency-textfield'; +import {Card, CardContent, CardHeader, Divider } from '@mui/material'; + + +const steps = [ + { + label: 'Request Access As Artist', + description: `In order to start selling your art on our platform, you need to request access. Please include links to your social media and tag or DM us on the platform (@RequestDotBox). We may reach out for further verification and examples of your work.`, + }, + { + label: 'Onboard On Stripe', + description: + 'Our platform uses Stripe as a payment processor. You will be required to onboard with them with all of your payout information and business information.', + }, + { + label: 'Setup Your Portfolio', + description: `This is where you can setup your initial portfolio. You can upload any image format file to your portfolio. It will be automatically displayed on your artist page. You can add and remove from this later.`, + }, +]; + +export default function Onboarding() { + const [activeStep, setActiveStep] = React.useState(0); + const [sellerRequestData, setSellerRequestData] = React.useState(null); + const [profileData, setSellerProfileData] = React.useState(null); + const [isStripeOnboarded, setIsStripeOnboarded] = React.useState(false); + const [onBoardUrl, setOnBoardUrl] = React.useState(""); + + + + const handleNext = () => { + setActiveStep((prevActiveStep) => prevActiveStep + 1); + }; + + const handleBack = () => { + setActiveStep((prevActiveStep) => prevActiveStep - 1); + }; + + const handleReset = () => { + setActiveStep(0); + }; + + const getData = async () => { + const onboardCheckRequest = await fetch('/api/artist/onboarded', { method: "GET" }); + const onboardCheckResponse = await onboardCheckRequest.json(); + setIsStripeOnboarded(onboardCheckResponse["onboarded"]); + const onboardUrlRequest = await fetch('/api/artist/onboardurl', { method: "GET" }); + const onboardUrlResponse = await onboardUrlRequest.json(); + setOnBoardUrl(onboardUrlResponse["onboardUrl"]); + const response = await fetch('/api/artist/request'); + const sellerRequest = await response.json(); + setSellerRequestData(sellerRequest); + const profileResponse = await fetch('/api/artist/profile'); + const sellerProfile = await profileResponse.json(); + setSellerProfileData(sellerProfile); + + setTimeout(getData, 5000); // Poll every 5 seconds (adjust as needed) + } + React.useEffect(() => { + getData(); + }, []); + + const requestButton = () => { + fetch('/api/artist/newRequest').then((response) => { + if (response.ok) { + fetch('/api/artist/request').then((requestResponse) => { + requestResponse.json().then((sellerRequest) => { + setSellerRequestData(sellerRequest); + }); + }); + } + }); + } + + let formattedTime = "" + if (sellerRequestData) { + const date = new Date(sellerRequestData["requestDate"]); + formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format + } + + return ( + + + {steps.map((step, index) => ( + + Last step + ) : null + } + > + {step.label} + + {(index==0) ? ( + + + + {step.description} + + {(sellerRequestData && Object.keys(sellerRequestData).length>0) ? ( + + + + ):( + + + + )} + + +
+ {(sellerRequestData && Object.keys(sellerRequestData).length>0) ? ( + (sellerRequestData["accepted"]) ? ( + + ) : ( + + ) + ): + ( + + + )} +
+
+
+ ): null} + {(index==1) ? ( + + + + {step.description} + + + +
+ {isStripeOnboarded==true ? ( + + ):( + + + )} +
+
+
+ ): null} + {(index==2) ? ( + + + + {step.description} + + + + + + +
+ +
+
+
+ ): null} +
+ ))} +
+ {activeStep === steps.length && ( + + We are setting up your account please wait. + + )} +
+ ); +} \ No newline at end of file diff --git a/components/Orders.tsx b/components/Orders.tsx new file mode 100644 index 0000000..8f173c7 --- /dev/null +++ b/components/Orders.tsx @@ -0,0 +1,33 @@ +import * as React from 'react'; +import { DataGrid, GridColDef, GridValueGetterParams } from '@mui/x-data-grid'; +import { Button } from '@mui/material'; + +const columns: GridColDef[] = [ + { field: 'id', headerName: 'ID', width: 70 }, + { field: 'artist', headerName: 'Artist', width: 130 }, + { field: 'status', headerName: 'Status', width: 130 }, + { field: 'action', headerName: 'Action', width: 180, renderCell: (params) => { + return (); + }}, +]; + +const rows = [ + { id: 1, artist:'Neroshi', status: 'Pending'}, +]; + +export default function Orders() { + return ( +
+ +
+ ); +} diff --git a/components/artistDashboardRequest.tsx b/components/artistDashboardRequest.tsx deleted file mode 100644 index a8182ac..0000000 --- a/components/artistDashboardRequest.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import * as React from 'react'; -import { useEffect, useState } from "react"; -import { Grid, Card, CardContent, Typography } from '@mui/material'; -import CircularProgress from '@mui/material/CircularProgress'; -import Box from '@mui/material/Box'; - - -const ArtistDashboardRequest = () => { - const [sellerRequestData, setSellerRequestData] = useState(null); - - const getData = async () => { - const response = await fetch('/api/artist/profile'); - const sellerProfile = await response.json(); - setSellerRequestData(sellerProfile); - } - useEffect(() => { - getData(); - }, []); - - let formattedTime = "" - if (sellerRequestData) { - const date = new Date(sellerRequestData["requestDate"]); - formattedTime = date.toLocaleTimeString('en-US', { month: 'long', day: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); // Example format - } - - const requestButton = () => { - fetch('/api/artist/newRequest').then((response) => { - if (response.ok) { - fetch('/api/artist/request').then((requestResponse) => { - requestResponse.json().then((sellerRequest) => { - setSellerRequestData(sellerRequest); - getData(); - }); - }); - } - }); - } - - return ( - (sellerRequestData ? ( - - - - - Request Status - - {(sellerRequestData["accepted"] ? ( - Accepted - ) : ( - Pending - ))} - Request submitted on {formattedTime ?? ''} - - - ) : ( - - - - Loading - - - - - )) - ) - } -export default ArtistDashboardRequest \ No newline at end of file diff --git a/pages/dashboard.tsx b/components/withOnboardingRequired.tsx similarity index 100% rename from pages/dashboard.tsx rename to components/withOnboardingRequired.tsx diff --git a/configs/themeConfig.tsx b/configs/themeConfig.tsx new file mode 100644 index 0000000..1d02c6b --- /dev/null +++ b/configs/themeConfig.tsx @@ -0,0 +1,36 @@ +// ** MUI Imports +import { PaletteMode } from '@mui/material' + +// ** Types +import { ContentWidth } from '../core/layouts/types' + +type ThemeConfig = { + mode: PaletteMode + templateName: string + routingLoader: boolean + disableRipple: boolean + navigationSize: number + menuTextTruncate: boolean + contentWidth: ContentWidth + responsiveFontSizes: boolean +} + +const themeConfig: ThemeConfig = { + // ** Layout Configs + templateName: 'Request.Box' /* App Name */, + mode: 'light' /* light | dark */, + contentWidth: 'boxed' /* full | boxed */, + + // ** Routing Configs + routingLoader: true /* true | false */, + + // ** Navigation (Menu) Configs + menuTextTruncate: true /* true | false */, + navigationSize: 260 /* Number in PX(Pixels) /*! Note: This is for Vertical navigation menu only */, + + // ** Other Configs + responsiveFontSizes: true /* true | false */, + disableRipple: false /* true | false */ +} + +export default themeConfig diff --git a/core/components/card-statistics/card-stats-vertical/index.tsx b/core/components/card-statistics/card-stats-vertical/index.tsx new file mode 100644 index 0000000..04efd09 --- /dev/null +++ b/core/components/card-statistics/card-stats-vertical/index.tsx @@ -0,0 +1,54 @@ +// ** MUI Imports +import Box from '@mui/material/Box' +import Card from '@mui/material/Card' +import Avatar from '@mui/material/Avatar' +import IconButton from '@mui/material/IconButton' +import Typography from '@mui/material/Typography' +import CardContent from '@mui/material/CardContent' + +// ** Icons Imports +import DotsVertical from 'mdi-material-ui/DotsVertical' + +// ** Types Imports +import { CardStatsVerticalProps } from '../core/components/card-statistics/types' + +const CardStatsVertical = (props: CardStatsVerticalProps) => { + // ** Props + const { title, subtitle, color, icon, stats, trend, trendNumber } = props + + return ( + + + + + {icon} + + + + + + {title} + + + {stats} + + + {trendNumber} + + + {subtitle} + + + ) +} + +export default CardStatsVertical + +CardStatsVertical.defaultProps = { + color: 'primary', + trend: 'positive' +} diff --git a/core/components/card-statistics/types.ts b/core/components/card-statistics/types.ts new file mode 100644 index 0000000..0d5371b --- /dev/null +++ b/core/components/card-statistics/types.ts @@ -0,0 +1,15 @@ +// ** React Imports +import { ReactNode } from 'react' + +// ** Types +import { ThemeColor } from '../core/layouts/types' + +export type CardStatsVerticalProps = { + title: string + stats: string + icon: ReactNode + subtitle: string + color?: ThemeColor + trendNumber: string + trend?: 'positive' | 'negative' +} diff --git a/core/components/react-apexcharts/index.tsx b/core/components/react-apexcharts/index.tsx new file mode 100644 index 0000000..e8d2b2d --- /dev/null +++ b/core/components/react-apexcharts/index.tsx @@ -0,0 +1,7 @@ +// ** Next Import +import dynamic from 'next/dynamic' + +// ! To avoid 'Window is not defined' error +const ReactApexcharts = dynamic(() => import('react-apexcharts'), { ssr: false }) + +export default ReactApexcharts diff --git a/core/components/scroll-to-top/index.tsx b/core/components/scroll-to-top/index.tsx new file mode 100644 index 0000000..30bed5d --- /dev/null +++ b/core/components/scroll-to-top/index.tsx @@ -0,0 +1,47 @@ +// ** React Imports +import { ReactNode } from 'react' + +// ** MUI Imports +import Zoom from '@mui/material/Zoom' +import { styled } from '@mui/material/styles' +import useScrollTrigger from '@mui/material/useScrollTrigger' + +interface ScrollToTopProps { + className?: string + children: ReactNode +} + +const ScrollToTopStyled = styled('div')(({ theme }) => ({ + zIndex: 11, + position: 'fixed', + right: theme.spacing(6), + bottom: theme.spacing(10) +})) + +const ScrollToTop = (props: ScrollToTopProps) => { + // ** Props + const { children, className } = props + + // ** init trigger + const trigger = useScrollTrigger({ + threshold: 400, + disableHysteresis: true + }) + + const handleClick = () => { + const anchor = document.querySelector('body') + if (anchor) { + anchor.scrollIntoView({ behavior: 'smooth' }) + } + } + + return ( + + + {children} + + + ) +} + +export default ScrollToTop diff --git a/core/context/settingsContext.tsx b/core/context/settingsContext.tsx new file mode 100644 index 0000000..adf2df5 --- /dev/null +++ b/core/context/settingsContext.tsx @@ -0,0 +1,47 @@ +// ** React Imports +import { createContext, useState, ReactNode } from 'react' + +// ** MUI Imports +import { PaletteMode } from '@mui/material' + +// ** ThemeConfig Import +import themeConfig from '../../configs/themeConfig' + +// ** Types Import +import { ThemeColor, ContentWidth } from '../../core/layouts/types' + +export type Settings = { + mode: PaletteMode + themeColor: ThemeColor + contentWidth: ContentWidth +} + +export type SettingsContextValue = { + settings: Settings + saveSettings: (updatedSettings: Settings) => void +} + +const initialSettings: Settings = { + themeColor: 'primary', + mode: themeConfig.mode, + contentWidth: themeConfig.contentWidth +} + +// ** Create Context +export const SettingsContext = createContext({ + saveSettings: () => null, + settings: initialSettings +}) + +export const SettingsProvider = ({ children }: { children: ReactNode }) => { + // ** State + const [settings, setSettings] = useState({ ...initialSettings }) + + const saveSettings = (updatedSettings: Settings) => { + setSettings(updatedSettings) + } + + return {children} +} + +export const SettingsConsumer = SettingsContext.Consumer diff --git a/core/hooks/useSettings.ts b/core/hooks/useSettings.ts new file mode 100644 index 0000000..bdf3047 --- /dev/null +++ b/core/hooks/useSettings.ts @@ -0,0 +1,4 @@ +import { useContext } from 'react' +import { SettingsContext, SettingsContextValue } from '../../core/context/settingsContext' + +export const useSettings = (): SettingsContextValue => useContext(SettingsContext) diff --git a/core/layouts/BlankLayout.tsx b/core/layouts/BlankLayout.tsx new file mode 100644 index 0000000..7c86693 --- /dev/null +++ b/core/layouts/BlankLayout.tsx @@ -0,0 +1,40 @@ +// ** MUI Imports +import { styled } from '@mui/material/styles' +import Box, { BoxProps } from '@mui/material/Box' + +// ** Types +import { BlankLayoutProps } from './types' + +// Styled component for Blank Layout component +const BlankLayoutWrapper = styled(Box)(({ theme }) => ({ + height: '100vh', + + // For V1 Blank layout pages + '& .content-center': { + display: 'flex', + minHeight: '100vh', + alignItems: 'center', + justifyContent: 'center', + padding: theme.spacing(5) + }, + + // For V2 Blank layout pages + '& .content-right': { + display: 'flex', + minHeight: '100vh', + overflowX: 'hidden', + position: 'relative' + } +})) + +const BlankLayout = ({ children }: BlankLayoutProps) => { + return ( + + + {children} + + + ) +} + +export default BlankLayout diff --git a/core/layouts/VerticalLayout.tsx b/core/layouts/VerticalLayout.tsx new file mode 100644 index 0000000..5e50e70 --- /dev/null +++ b/core/layouts/VerticalLayout.tsx @@ -0,0 +1,118 @@ +// ** React Imports +import { useState } from 'react' + +// ** MUI Imports +import Fab from '@mui/material/Fab' +import { styled } from '@mui/material/styles' +import Box, { BoxProps } from '@mui/material/Box' + +// ** Icons Imports +import ArrowUp from 'mdi-material-ui/ArrowUp' + +// ** Theme Config Import +import themeConfig from '../../configs/themeConfig' + +// ** Type Import +import { LayoutProps } from '../../core/layouts/types' + +// ** Components +import AppBar from './components/vertical/appBar' +import Navigation from './components/vertical/navigation' +import Footer from './components/shared-components/footer' +import ScrollToTop from '../../core/components/scroll-to-top' + +// ** Styled Component +import DatePickerWrapper from '../../core/styles/libs/react-datepicker' + +const VerticalLayoutWrapper = styled('div')({ + height: '100%', + display: 'flex' +}) + +const MainContentWrapper = styled(Box)({ + flexGrow: 1, + minWidth: 0, + display: 'flex', + minHeight: '100vh', + flexDirection: 'column' +}) + +const ContentWrapper = styled('main')(({ theme }) => ({ + flexGrow: 1, + width: '100%', + padding: theme.spacing(6), + transition: 'padding .25s ease-in-out', + [theme.breakpoints.down('sm')]: { + paddingLeft: theme.spacing(4), + paddingRight: theme.spacing(4) + } +})) + +const VerticalLayout = (props: LayoutProps) => { + // ** Props + const { settings, children, scrollToTop } = props + + // ** Vars + const { contentWidth } = settings + const navWidth = themeConfig.navigationSize + + // ** States + const [navVisible, setNavVisible] = useState(false) + + // ** Toggle Functions + const toggleNavVisibility = () => setNavVisible(!navVisible) + + return ( + <> + + {/* Navigation Menu */} + + + {/* AppBar Component */} + + + {/* Content */} + + {children} + + + {/* Footer Component */} +