(false);
+
+ // Function to toggle the chat pane visibility
+ const toggleChat = () => {
+ setShowChat(!showChat);
+ // When opening, ensure it's not minimized
+ if (!showChat) {
+ setIsMinimized(false);
+ }
+ };
+
+ // Function to toggle minimize/maximize the chat pane
+ const toggleMinimize = () => {
+ setIsMinimized(!isMinimized);
+ };
+
+ // Function to close the chat pane
+ const closeChat = () => {
+ setShowChat(false);
+ setIsMinimized(false); // Reset minimize state when closing
+ };
+ return(
+
+ {/* Floating Action Button */}
+ {!showChat && }
+
+
+
+
+
+ )
+
+}
+
+export default FloatingChatButton;
\ No newline at end of file
diff --git a/ditch-the-agent/src/components/base/IconifyIcon.tsx b/ditch-the-agent/src/components/base/IconifyIcon.tsx
new file mode 100644
index 0000000..bde5454
--- /dev/null
+++ b/ditch-the-agent/src/components/base/IconifyIcon.tsx
@@ -0,0 +1,12 @@
+import { Box, BoxProps } from '@mui/material';
+import { Icon, IconProps } from '@iconify/react';
+
+interface IconifyProps extends BoxProps {
+ icon: IconProps['icon'];
+}
+
+const IconifyIcon = ({ icon, width, height, ...rest }: IconifyProps) => {
+ return ;
+};
+
+export default IconifyIcon;
diff --git a/ditch-the-agent/src/components/base/Image.tsx b/ditch-the-agent/src/components/base/Image.tsx
new file mode 100644
index 0000000..388314e
--- /dev/null
+++ b/ditch-the-agent/src/components/base/Image.tsx
@@ -0,0 +1,14 @@
+import { Box, SxProps } from '@mui/material';
+import { ImgHTMLAttributes } from 'react';
+
+interface ImageProps extends ImgHTMLAttributes {
+ src: string;
+ alt?: string;
+ sx?: SxProps;
+}
+
+const Image = ({ src, alt, sx, ...rest }: ImageProps) => (
+
+);
+
+export default Image;
diff --git a/ditch-the-agent/src/components/base/ReactEchart.tsx b/ditch-the-agent/src/components/base/ReactEchart.tsx
new file mode 100644
index 0000000..5fbc3ca
--- /dev/null
+++ b/ditch-the-agent/src/components/base/ReactEchart.tsx
@@ -0,0 +1,31 @@
+import { Box, BoxProps } from '@mui/material';
+import { EChartsReactProps } from 'echarts-for-react';
+import EChartsReactCore from 'echarts-for-react/lib/core';
+import ReactEChartsCore from 'echarts-for-react/lib/core';
+import { forwardRef } from 'react';
+
+export interface ReactEchartProps extends BoxProps {
+ echarts: EChartsReactProps['echarts'];
+ option: EChartsReactProps['option'];
+}
+
+const ReactEchart = forwardRef(
+ ({ option, ...rest }, ref) => {
+ return (
+
+ );
+ },
+);
+
+export default ReactEchart;
diff --git a/ditch-the-agent/src/components/loading/PageLoader.tsx b/ditch-the-agent/src/components/loading/PageLoader.tsx
new file mode 100644
index 0000000..06935f8
--- /dev/null
+++ b/ditch-the-agent/src/components/loading/PageLoader.tsx
@@ -0,0 +1,28 @@
+import { Box, CircularProgress, Stack, StackOwnProps } from '@mui/material';
+import { caribbeanGreen, downy, orange, watermelon } from 'theme/colors';
+
+const PageLoader = (props: StackOwnProps) => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default PageLoader;
diff --git a/ditch-the-agent/src/components/loading/Splash.tsx b/ditch-the-agent/src/components/loading/Splash.tsx
new file mode 100644
index 0000000..a2c414f
--- /dev/null
+++ b/ditch-the-agent/src/components/loading/Splash.tsx
@@ -0,0 +1,11 @@
+import { Box, LinearProgress } from '@mui/material';
+
+const Splash = () => {
+ return (
+
+
+
+ );
+};
+
+export default Splash;
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Education/EducationDetail.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Education/EducationDetail.tsx
new file mode 100644
index 0000000..dfacc51
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Education/EducationDetail.tsx
@@ -0,0 +1,65 @@
+
+import { ReactElement } from 'react';
+import { Card, CardContent, CardMedia, Divider, Stack, Typography } from '@mui/material';
+import { DataGrid } from '@mui/x-data-grid';
+
+type EducationDetailProps = {
+
+}
+
+
+
+const EducationDetail = (): ReactElement => {
+ return(
+ ({
+ boxShadow: theme.shadows[4],
+ width: 1,
+ height: 'auto',
+ })}
+ >
+
+
+
+ {'Video'}
+
+
+
+
+ theme.shadows[4]}
+ height={1}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default EducationDetail;
\ No newline at end of file
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Education/EducationInfo.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Education/EducationInfo.tsx
new file mode 100644
index 0000000..5419a56
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Education/EducationInfo.tsx
@@ -0,0 +1,214 @@
+
+import { ReactElement } from 'react';
+import { Box, Card, CardContent, CardMedia, Divider, LinearProgress, Stack, Typography } from '@mui/material';
+import { DataGrid, GridRenderCellParams } from '@mui/x-data-grid';
+import { useNavigate } from 'react-router-dom'
+import { renderProgress } from '@mui/x-data-grid-generator';
+import { GridColDef } from '@mui/x-data-grid';
+
+type EducationInfoProps = {
+ title: string;
+}
+interface Row {
+ id: number;
+ task: string;
+ progress: number; // Value from 0 to 100 for the progress bar
+}
+export const EducationInfoCards = () => {
+ return(
+
+
+
+
+
+ )
+}
+
+const EducationInfo = ({ title }: EducationInfoProps): ReactElement => {
+
+ const navigate = useNavigate();
+
+ const columns: GridColDef[] = [
+ {
+ field: 'id',
+ headerName: 'ID'
+ },
+ {
+ field: 'title',
+ headerName: 'Title',
+ flex: 1,
+ },
+
+ {
+ field: 'category',
+ headerName: 'Category',
+ flex: 1,
+ },
+
+ {
+ field: 'progress',
+ headerName: 'Progress',
+ flex: 1,
+ renderCell: (params: GridRenderCellParams) => {
+ const progressValue = params.value; // Access the progress value from the row data
+
+ return (
+
+
+
+
+
+ {`${progressValue}%`}
+
+
+ );
+ },
+ },
+ {
+ field: 'status',
+ headerName: 'Status',
+ flex: 1,
+ },
+
+ ]
+
+ const rows = [
+ {
+ id: 1,
+ title: "How to Research Comparable Properties Like a Pro",
+ category: "Pricing Strategy",
+ progress: 100,
+ status: "COMPLETED",
+ },
+ {
+ id: 2,
+ title: "Understanding Price Per Square Foot in Your Neighborhood",
+ category: "Pricing Strategy",
+ progress: 100,
+ status: "COMPLETED",
+ },
+ {
+ id: 3,
+ title: "Psychological Pricing: Why $399,900 Works Better Than $400,000",
+ category: "Pricing Strategy",
+ progress: 100,
+ status: "COMPLETED",
+ },
+ {
+ id: 4,
+ title: "When and How to Adjust Your Asking Price",
+ category: "Pricing Strategy",
+ progress: 100,
+ status: "COMPLETED",
+ },
+ {
+ id: 5,
+ title: "Handling Lowball Offers: Strategies That Work",
+ category: "Pricing Strategy",
+ progress: 100,
+ status: "COMPLETED",
+ },
+
+
+
+
+
+
+
+
+
+ {
+ id: 6,
+ title: "The Ultimate Home Staging Checklist for FSBO Sellers",
+ category: "Property Preparation",
+ progress: 90,
+ status: "IN_PROGRESS",
+ },
+ {
+ id: 7,
+ title: "DIY Curb Appeal Upgrades Under $500",
+ category: "Property Preparation",
+ progress: 80,
+ status: "IN_PROGRESS",
+ },
+ {
+ id: 8,
+ title: "Decluttering Secrets for Faster Sales",
+ category: "Property Preparation",
+ progress: 5,
+ status: "IN_PROGRESS",
+ },
+ {
+ id: 9,
+ title: "Professional Photography Tips Using Just Your Smartphone",
+ category: "Property Preparation",
+ progress: 50,
+ status: "IN_PROGRESS",
+ },
+ {
+ id: 10,
+ title: "Deep Cleaning Checklist Before Listing",
+ category: "Property Preparation",
+ progress: 50,
+ status: "IN_PROGRESS",
+ },
+ {
+ id: 11,
+ title: "How to stage a home",
+ category: "",
+ progress: 0,
+ status: "NOT_STARTED",
+ },
+ ]
+ return(
+ ({
+ boxShadow: theme.shadows[4],
+ width: 1,
+ height: 'auto',
+ })}
+ >
+
+
+
+ {title}
+
+
+
+
+ theme.shadows[4]}
+ height={1}
+ >
+ 70}
+ rows={rows}
+ columns={columns}
+ onRowClick={(event) => navigate('lesson')}
+ />
+
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default EducationInfo;
\ No newline at end of file
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Property/HomePriceEstimate.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Property/HomePriceEstimate.tsx
new file mode 100644
index 0000000..155819e
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Property/HomePriceEstimate.tsx
@@ -0,0 +1,54 @@
+import { ReactElement } from 'react';
+import { Card, CardContent, CardMedia, Divider, Stack, Typography } from '@mui/material';
+
+const HomePriceEstimate = (): ReactElement => {
+ return(
+ ({
+ boxShadow: theme.shadows[4],
+ width: 1,
+ height: 'auto',
+ })}
+ >
+
+
+
+ Home Price Estimate
+
+
+
+
+
+ $700,500k
+
+
+ Estimated value range: $335,000 - $365,000
+
+
+ Last updated: June 15, 2023
+
+
+
+ This estimate is based on recent sales and market trends in your area.
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default HomePriceEstimate;
\ No newline at end of file
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Property/LoanDetailsCard.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Property/LoanDetailsCard.tsx
new file mode 100644
index 0000000..309b951
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Property/LoanDetailsCard.tsx
@@ -0,0 +1,57 @@
+import { ReactElement } from 'react';
+import { Card, CardContent, CardMedia, LinearProgress, Stack, Typography } from '@mui/material';
+
+const LoanDetailsCard = (): ReactElement => {
+ return(
+ ({
+ boxShadow: theme.shadows[4],
+ width: 1,
+ height: 'auto',
+ })}
+ >
+
+
+
+ Loan Details
+
+
+
+
+
+
+ Length: 30 year
+
+
+ Start Date: Dec 2020
+
+
+ Intrest Rate: 3%
+
+
+ Intrest Rate: 3%
+
+
+ PMI: 3%
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default LoanDetailsCard;
\ No newline at end of file
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Property/MarketStatistics.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Property/MarketStatistics.tsx
new file mode 100644
index 0000000..d5b02fc
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Property/MarketStatistics.tsx
@@ -0,0 +1,53 @@
+import { ReactElement } from 'react';
+import { Card, CardContent, CardMedia, Stack, Typography } from '@mui/material';
+
+const MarketStatistics = (): ReactElement => {
+ return(
+ ({
+ boxShadow: theme.shadows[4],
+ width: 1,
+ height: 'auto',
+ })}
+ >
+
+
+
+ Market Statistics
+
+
+
+
+
+ Average Market Time: 10 days on the market
+
+
+ Price per Sq Ft: $189 (neighborhood avg $175)
+
+
+ Listing Activity: 5 homes sold in the last 30 days
+
+
+ Compariable asking vs selling price: +$10k
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default MarketStatistics;
\ No newline at end of file
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Property/PhotoGalleryCard.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Property/PhotoGalleryCard.tsx
new file mode 100644
index 0000000..b1b7e78
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Property/PhotoGalleryCard.tsx
@@ -0,0 +1,156 @@
+import { ReactElement } from 'react';
+import { Card, CardContent, CardMedia, IconButton, ImageList, ImageListItem, ImageListItemBar, Stack, Typography } from '@mui/material';
+
+function srcset(image: string, width: number, height: number, rows = 1, cols = 1) {
+ return {
+ src: `${image}?w=${width * cols}&h=${height * rows}&fit=crop&auto=format`,
+ srcSet: `${image}?w=${width * cols}&h=${
+ height * rows
+ }&fit=crop&auto=format&dpr=2 2x`,
+ };
+}
+
+const PhotoGalleryCard = (): ReactElement => {
+ const itemData = [
+ {
+ img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
+ title: 'Breakfast',
+ author: '@bkristastucchio',
+ featured: true,
+ },
+ {
+ img: 'https://images.unsplash.com/photo-1551782450-a2132b4ba21d',
+ title: 'Burger',
+ author: '@rollelflex_graphy726',
+ },
+ {
+ img: 'https://images.unsplash.com/photo-1522770179533-24471fcdba45',
+ title: 'Camera',
+ author: '@helloimnik',
+ },
+ {
+ img: 'https://images.unsplash.com/photo-1444418776041-9c7e33cc5a9c',
+ title: 'Coffee',
+ author: '@nolanissac',
+ },
+ {
+ img: 'https://images.unsplash.com/photo-1533827432537-70133748f5c8',
+ title: 'Hats',
+ author: '@hjrc33',
+ },
+ {
+ img: 'https://images.unsplash.com/photo-1558642452-9d2a7deb7f62',
+ title: 'Honey',
+ author: '@arwinneil',
+ featured: true,
+ },
+ {
+ img: 'https://images.unsplash.com/photo-1516802273409-68526ee1bdd6',
+ title: 'Basketball',
+ author: '@tjdragotta',
+ },
+ {
+ img: 'https://images.unsplash.com/photo-1518756131217-31eb79b20e8f',
+ title: 'Fern',
+ author: '@katie_wasserman',
+ },
+ {
+ img: 'https://images.unsplash.com/photo-1597645587822-e99fa5d45d25',
+ title: 'Mushrooms',
+ author: '@silverdalex',
+ },
+ {
+ img: 'https://images.unsplash.com/photo-1567306301408-9b74779a11af',
+ title: 'Tomato basil',
+ author: '@shelleypauls',
+ },
+ {
+ img: 'https://images.unsplash.com/photo-1471357674240-e1a485acb3e1',
+ title: 'Sea star',
+ author: '@peterlaster',
+ },
+ {
+ img: 'https://images.unsplash.com/photo-1589118949245-7d38baf380d6',
+ title: 'Bike',
+ author: '@southside_customs',
+ },
+ ];
+ return(
+ ({
+ boxShadow: theme.shadows[4],
+ width: 1,
+ height: 'auto',
+ })}
+ >
+
+
+
+ Photo Gallery
+
+
+
+
+ {itemData.map((item) => {
+ const cols = item.featured ? 2 : 1;
+ const rows = item.featured ? 2 : 1;
+
+ return (
+
+
+
+
+
+ }
+ actionPosition="left"
+ />
+
+ );
+ })}
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default PhotoGalleryCard;
\ No newline at end of file
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyDetailsCard.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyDetailsCard.tsx
new file mode 100644
index 0000000..7e7c702
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyDetailsCard.tsx
@@ -0,0 +1,80 @@
+import { ReactElement } from 'react';
+import { Card, CardContent, CardMedia, Divider, Stack, Typography } from '@mui/material';
+import Grid from '@mui/material/Unstable_Grid2';
+
+const PropertyDetailsCard = (): ReactElement => {
+ return(
+ ({
+ boxShadow: theme.shadows[4],
+ width: 1,
+ height: 'auto',
+ })}
+ >
+
+
+
+ Property Details
+
+
+
+
+
+
+ Property Type: Single Family Home
+
+
+
+
+
+ Year Built: 1998
+
+
+
+
+
+ Lot Size: 0.25 acres
+
+
+
+
+
+ Bedrooms: 3
+
+
+
+
+
+ Bathrooms: 2
+
+
+
+
+
+ Square Feet: 1,850
+
+
+
+
+
+ Beautifully maintained home in desirable neighborhood. Features updated kitchen with granite countertops, hardwood floors throughout main living areas, spacious master suite, and large backyard with deck. Excellent schools nearby.
+
+
+
+
+
+ )
+
+}
+
+export default PropertyDetailsCard;
\ No newline at end of file
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyInfo.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyInfo.tsx
new file mode 100644
index 0000000..f2ae7ce
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyInfo.tsx
@@ -0,0 +1,68 @@
+
+import { ReactElement } from 'react';
+import { Card, CardContent, CardMedia, Stack, Typography } from '@mui/material';
+
+type EducationInfoProps = {
+ title: string;
+}
+
+export const ProperyInfoCards = () => {
+ return(
+
+
+
+
+
+ )
+}
+
+const PropertyInfo = ({ title }: EducationInfoProps): ReactElement => {
+ return(
+ ({
+ boxShadow: theme.shadows[4],
+ width: 1,
+ height: 'auto',
+ })}
+ >
+
+
+
+ {title}
+
+
+
+
+
+ Estimated Home Value: $700,500k
+
+
+ Estimated Savings: $24,000k
+
+
+ Compariable Time on market: 5 days
+
+
+ Compariable asking vs selling price: +$10k
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default PropertyInfo;
\ No newline at end of file
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyListingCard.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyListingCard.tsx
new file mode 100644
index 0000000..b65e035
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyListingCard.tsx
@@ -0,0 +1,50 @@
+import { ReactElement } from 'react';
+import { Card, CardContent, CardMedia, Stack, Typography } from '@mui/material';
+
+const PropertyListingCard = (): ReactElement => {
+ return(
+ ({
+ boxShadow: theme.shadows[4],
+ width: 1,
+ height: 'auto',
+ })}
+ >
+
+
+
+ MLS Listing
+
+
+
+
+
+ Zillow
+
+
+ Redfin
+
+
+ Realtor
+
+
+
+
+
+
+
+
+
+ )
+
+}
+
+export default PropertyListingCard;
\ No newline at end of file
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyValueGraphCard.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyValueGraphCard.tsx
new file mode 100644
index 0000000..9adc989
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Property/PropertyValueGraphCard.tsx
@@ -0,0 +1,191 @@
+import { ReactElement, useRef, useState } from 'react';
+import { Box, Button, Stack, Typography, useTheme } from '@mui/material';
+import EChartsReactCore from 'echarts-for-react/lib/core';
+
+import { LineSeriesOption } from 'echarts';
+import RevenueChart from '../Sales/Revenue/RevenueChart';
+
+const PropertyValueGraphCard = (): ReactElement => {
+ const theme = useTheme();
+ const chartRef = useRef(null);
+
+ const lineChartColors = [theme.palette.secondary.main, theme.palette.primary.main];
+
+ const legendData = [
+ { name: 'Loan Value', icon: 'circle' },
+ { name: 'Home Value', icon: 'circle' },
+ ];
+
+ const seriesData: LineSeriesOption[] = [
+ {
+ id: 1,
+ data: [450000,
+449200,
+448400,
+447600,
+446800,
+446000,
+445200,
+444400,
+443600,
+442800,
+442000,
+441200,
+440400,
+439600,
+438800,
+438000,
+437200,
+436400,
+435600,
+434800,
+434000,
+433200,
+432400,
+431600,
+430800,
+430000],
+ type: 'line',
+ smooth: true,
+ color: lineChartColors[0],
+ name: 'Loan Value',
+ legendHoverLink: true,
+ showSymbol: true,
+ symbolSize: 12,
+ lineStyle: {
+ width: 5,
+ },
+ },
+ {
+ id: 2,
+ data: [450000,
+452000,
+453000,
+452000,
+452000,
+451000,
+450000,
+452000,
+452000,
+454000,
+453000,
+452000,
+452000,
+452000,
+451000,
+451000,
+451000,
+451000,
+450000,
+451000,
+452000,
+453000,
+454000,
+453000,
+455000,
+454000],
+ type: 'line',
+ smooth: true,
+ color: lineChartColors[1],
+ name: 'Home Value',
+ legendHoverLink: true,
+ showSymbol: false,
+ symbolSize: 12,
+ lineStyle: {
+ width: 5,
+ },
+ },
+ ];
+ const [revenueAdType, setRevenueAdType] = useState({
+ 'Loan Value': false,
+ 'Home Value': false,
+ });
+
+ const toggleClicked = (name: string) => {
+ setRevenueAdType((prevState: any) => ({
+ ...prevState,
+ [name]: !prevState[name],
+ }));
+ };
+
+ const onChartLegendSelectChanged = (name: string) => {
+ if (chartRef.current) {
+ const instance = chartRef.current.getEchartsInstance();
+ instance.dispatchAction({
+ type: 'legendToggleSelect',
+ name: name,
+ });
+ }
+ };
+
+ return(
+
+
+
+ Home and Loan Value
+
+
+ {Array.isArray(seriesData) &&
+ seriesData.map((dataItem, index) => (
+ {
+ //toggleClicked(dataItem.name as string);
+ onChartLegendSelectChanged(dataItem.name as string);
+ }}
+ sx={{
+ justifyContent: 'flex-start',
+ p: 0,
+ borderRadius: 1,
+ opacity: revenueAdType[`${dataItem.name}`] ? 0.5 : 1,
+ }}
+ disableRipple
+ >
+ {' '}
+
+
+
+ {dataItem.name}
+
+
+
+ ))}
+
+
+
+
+
+
+ )
+}
+
+export default PropertyValueGraphCard;
\ No newline at end of file
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/BuyersProfile/BuyersProfile.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/BuyersProfile/BuyersProfile.tsx
new file mode 100644
index 0000000..84ab0c9
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/BuyersProfile/BuyersProfile.tsx
@@ -0,0 +1,196 @@
+import {
+ Box,
+ Button,
+ IconButton,
+ Menu,
+ MenuItem,
+ Stack,
+ Typography,
+ useTheme,
+} from '@mui/material';
+import IconifyIcon from 'components/base/IconifyIcon';
+import { ReactElement, useRef, useState } from 'react';
+import EChartsReactCore from 'echarts-for-react/lib/core';
+import BuyersProfileChart from './BuyersProfileChart';
+import { PieDataItemOption } from 'echarts/types/src/chart/pie/PieSeries.js';
+
+const BuyersProfile = (): ReactElement => {
+ const theme = useTheme();
+ const seriesData: PieDataItemOption[] = [
+ { value: 50, name: 'Male' },
+ { value: 35, name: 'Female' },
+ { value: 15, name: 'Others' },
+ ];
+ const legendData = [
+ { name: 'Male', icon: 'circle' },
+ { name: 'Female', icon: 'circle' },
+ { name: 'Others', icon: 'circle' },
+ ];
+ const pieChartColors = [
+ theme.palette.primary.main,
+ theme.palette.secondary.main,
+ theme.palette.error.main,
+ ];
+
+ const chartRef = useRef(null);
+ const [anchorEl, setAnchorEl] = useState(null);
+ const open = Boolean(anchorEl);
+ const [buyerGenderType, setBuyerGenderType] = useState({
+ Male: false,
+ Female: false,
+ Others: false,
+ });
+
+ const toggleClicked = (name: string) => {
+ setBuyerGenderType((prevState: any) => ({
+ ...prevState,
+ [name]: !prevState[name],
+ }));
+ };
+ const handleClick = (event: any) => {
+ setAnchorEl(event.target);
+ };
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ const onChartLegendSelectChanged = (name: string) => {
+ if (chartRef.current) {
+ const instance = chartRef.current.getEchartsInstance();
+ instance.dispatchAction({
+ type: 'legendToggleSelect',
+ name: name,
+ });
+ }
+ };
+
+ return (
+ theme.shadows[4],
+ }}
+ >
+
+
+ Buyers Profile
+
+
+
+
+
+
+ theme.spacing(0, 2.5, 2.5)}
+ >
+
+
+ {Array.isArray(seriesData) &&
+ seriesData.map((dataItem, index) => (
+ {
+ toggleClicked(dataItem.name as string);
+ onChartLegendSelectChanged(dataItem.name as string);
+ }}
+ sx={{
+ justifyContent: 'flex-start',
+ p: 0,
+ pr: 1,
+ borderRadius: 1,
+ opacity: buyerGenderType[`${dataItem.name}`] ? 0.5 : 1,
+ }}
+ disableRipple
+ >
+
+
+
+ {dataItem.name}
+
+
+ {dataItem.value}%
+
+
+
+ ))}
+
+
+
+ );
+};
+
+export default BuyersProfile;
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/BuyersProfile/BuyersProfileChart.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/BuyersProfile/BuyersProfileChart.tsx
new file mode 100644
index 0000000..9698168
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/BuyersProfile/BuyersProfileChart.tsx
@@ -0,0 +1,67 @@
+import { SxProps, useTheme } from '@mui/material';
+import ReactEchart from 'components/base/ReactEchart';
+import * as echarts from 'echarts';
+import { EChartsOption } from 'echarts-for-react';
+import EChartsReactCore from 'echarts-for-react/lib/core';
+import { PieDataItemOption } from 'echarts/types/src/chart/pie/PieSeries.js';
+import { useMemo } from 'react';
+
+type BuyersProfileChartProps = {
+ chartRef: React.MutableRefObject;
+ seriesData?: PieDataItemOption[];
+ legendData?: any;
+ colors?: string[];
+ sx?: SxProps;
+};
+
+const BuyersProfileChart = ({
+ chartRef,
+ seriesData,
+ legendData,
+ colors,
+ ...rest
+}: BuyersProfileChartProps) => {
+ const theme = useTheme();
+ const option: EChartsOption = useMemo(
+ () => ({
+ tooltip: {
+ trigger: 'item',
+ formatter: '{a} {b} : {c}%',
+ },
+ legend: {
+ show: false,
+ data: legendData,
+ },
+ series: [
+ {
+ name: 'Buyers Profile',
+ type: 'pie',
+ radius: ['65%', '90%'],
+ color: colors,
+ avoidLabelOverlap: true,
+ startAngle: -30,
+ clockwise: false,
+ label: {
+ show: false,
+ position: 'center',
+ },
+ emphasis: {
+ label: {
+ show: false,
+ },
+ scaleSize: 0,
+ },
+ labelLine: {
+ show: true,
+ },
+ data: seriesData,
+ },
+ ],
+ }),
+ [theme],
+ );
+
+ return ;
+};
+
+export default BuyersProfileChart;
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/NewCustomers/CustomerItem.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/NewCustomers/CustomerItem.tsx
new file mode 100644
index 0000000..c7a40b4
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/NewCustomers/CustomerItem.tsx
@@ -0,0 +1,42 @@
+import { Avatar, IconButton, Link, ListItem, Stack, Tooltip, Typography } from '@mui/material';
+import IconifyIcon from 'components/base/IconifyIcon';
+import { ReactElement } from 'react';
+
+type CustomerItemProps = {
+ name: string;
+ country: string;
+ avatar: string;
+};
+
+const CustomerItem = ({ name, country, avatar }: CustomerItemProps): ReactElement => {
+ const firstName = name.split(' ')[0];
+ return (
+ ({
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ padding: theme.spacing(1.25, 2.5),
+ })}
+ >
+
+
+
+
+
+
+ {name}
+
+
+ {country}
+
+
+
+
+
+
+
+ );
+};
+
+export default CustomerItem;
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/NewCustomers/NewCustomers.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/NewCustomers/NewCustomers.tsx
new file mode 100644
index 0000000..dbe19fb
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/NewCustomers/NewCustomers.tsx
@@ -0,0 +1,93 @@
+import { ReactElement, useState } from 'react';
+import { Box, IconButton, Menu, MenuItem, Stack, Typography } from '@mui/material';
+
+import IconifyIcon from 'components/base/IconifyIcon';
+import { customerList } from 'data/customers-list';
+import CustomerItem from './CustomerItem';
+
+const NewCustomers = (): ReactElement => {
+ const [anchorEl, setAnchorEl] = useState(null);
+ const open = Boolean(anchorEl);
+ const handleClick = (event: any) => {
+ setAnchorEl(event.target);
+ };
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ return (
+ theme.shadows[4],
+ }}
+ >
+
+
+ New Customers
+
+
+
+
+
+
+
+ {customerList.map((customer) => (
+
+ ))}
+
+
+ );
+};
+
+export default NewCustomers;
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/Revenue/Revenue.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/Revenue/Revenue.tsx
new file mode 100644
index 0000000..071d600
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/Revenue/Revenue.tsx
@@ -0,0 +1,141 @@
+import { ReactElement, useRef, useState } from 'react';
+import { Box, Button, Stack, Typography, useTheme } from '@mui/material';
+import EChartsReactCore from 'echarts-for-react/lib/core';
+import RevenueChart from './RevenueChart';
+import { LineSeriesOption } from 'echarts';
+
+const Revenue = (): ReactElement => {
+ const theme = useTheme();
+ const chartRef = useRef(null);
+
+ const lineChartColors = [theme.palette.secondary.main, theme.palette.primary.main];
+
+ const legendData = [
+ { name: 'Google ads', icon: 'circle' },
+ { name: 'Facebook ads', icon: 'circle' },
+ ];
+
+ const seriesData: LineSeriesOption[] = [
+ {
+ id: 1,
+ data: [65, 210, 175, 140, 105, 20, 120, 20],
+ type: 'line',
+ smooth: true,
+ color: lineChartColors[0],
+ name: 'Google ads',
+ legendHoverLink: true,
+ showSymbol: true,
+ symbolSize: 12,
+ lineStyle: {
+ width: 5,
+ },
+ },
+ {
+ id: 2,
+ data: [20, 125, 100, 30, 150, 300, 90, 180],
+ type: 'line',
+ smooth: true,
+ color: lineChartColors[1],
+ name: 'Facebook ads',
+ legendHoverLink: true,
+ showSymbol: false,
+ symbolSize: 12,
+ lineStyle: {
+ width: 5,
+ },
+ },
+ ];
+
+ const onChartLegendSelectChanged = (name: string) => {
+ if (chartRef.current) {
+ const instance = chartRef.current.getEchartsInstance();
+ instance.dispatchAction({
+ type: 'legendToggleSelect',
+ name: name,
+ });
+ }
+ };
+
+ const [revenueAdType, setRevenueAdType] = useState({
+ 'Google ads': false,
+ 'Facebook ads': false,
+ });
+
+ const toggleClicked = (name: string) => {
+ setRevenueAdType((prevState: any) => ({
+ ...prevState,
+ [name]: !prevState[name],
+ }));
+ };
+
+ return (
+
+
+
+ Revenue
+
+
+ {Array.isArray(seriesData) &&
+ seriesData.map((dataItem, index) => (
+ {
+ toggleClicked(dataItem.name as string);
+ onChartLegendSelectChanged(dataItem.name as string);
+ }}
+ sx={{
+ justifyContent: 'flex-start',
+ p: 0,
+ borderRadius: 1,
+ opacity: revenueAdType[`${dataItem.name}`] ? 0.5 : 1,
+ }}
+ disableRipple
+ >
+ {' '}
+
+
+
+ {dataItem.name}
+
+
+
+ ))}
+
+
+
+
+
+
+ );
+};
+
+export default Revenue;
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/Revenue/RevenueChart.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/Revenue/RevenueChart.tsx
new file mode 100644
index 0000000..4cb5560
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/Revenue/RevenueChart.tsx
@@ -0,0 +1,91 @@
+import { SxProps, useTheme } from '@mui/material';
+import ReactEchart from 'components/base/ReactEchart';
+import * as echarts from 'echarts';
+import EChartsReactCore from 'echarts-for-react/lib/core';
+import { LineSeriesOption } from 'echarts';
+import { useMemo } from 'react';
+import { EChartsOption } from 'echarts-for-react';
+
+type RevenueChartProps = {
+ chartRef: React.MutableRefObject;
+ seriesData?: LineSeriesOption[];
+ legendData?: any;
+ colors?: string[];
+ sx?: SxProps;
+};
+
+const RevenueChart = ({ chartRef, seriesData, legendData, colors, ...rest }: RevenueChartProps) => {
+ const theme = useTheme();
+
+ const option: EChartsOption = useMemo(
+ () => ({
+ xAxis: {
+ type: 'category',
+ data: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August'],
+ boundaryGap: false,
+ axisLine: {
+ show: true,
+ lineStyle: {
+ color: theme.palette.divider,
+ width: 1,
+ type: 'dashed',
+ },
+ },
+ axisLabel: {
+ show: true,
+ padding: 30,
+ color: theme.palette.text.secondary,
+ formatter: (value: any) => value.slice(0, 3),
+ fontFamily: theme.typography.body2.fontFamily,
+ },
+ axisTick: {
+ show: false,
+ },
+ },
+ yAxis: {
+ type: 'value',
+ min:420000,
+ max:480000,
+ splitNumber: 4,
+ axisLine: {
+ show: false,
+ },
+ axisLabel: {
+ show: true,
+ color: theme.palette.text.secondary,
+ align: 'center',
+ padding: [0, 20, 0, 0],
+ fontFamily: theme.typography.body2.fontFamily,
+ },
+ splitLine: {
+ interval: 5,
+ lineStyle: {
+ color: theme.palette.divider,
+ width: 1,
+ type: 'dashed',
+ },
+ },
+ },
+ grid: {
+ left: 60,
+ right: 30,
+ top: 30,
+ bottom: 90,
+ },
+ legend: {
+ show: false,
+ },
+ tooltip: {
+ show: true,
+ trigger: 'axis',
+ valueFormatter: (value: any) => '$' + value.toFixed(0),
+ },
+ series: seriesData,
+ }),
+ [theme],
+ );
+
+ return ;
+};
+
+export default RevenueChart;
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/SaleInfoSection/SaleInfo.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/SaleInfoSection/SaleInfo.tsx
new file mode 100644
index 0000000..e0a224c
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/SaleInfoSection/SaleInfo.tsx
@@ -0,0 +1,68 @@
+import { ReactElement } from 'react';
+import { Card, CardContent, CardMedia, Stack, Typography } from '@mui/material';
+import IconifyIcon from 'components/base/IconifyIcon';
+import Image from 'components/base/Image';
+import { currencyFormat } from 'helpers/format-functions';
+
+type SaleInfoProps = {
+ image?: string;
+ title: string;
+ sales: number;
+ increment: number;
+ date?: string;
+};
+
+const SaleInfo = ({ image, title, sales, increment, date }: SaleInfoProps): ReactElement => {
+ return (
+ ({
+ boxShadow: theme.shadows[4],
+ width: 1,
+ height: 'auto',
+ })}
+ >
+
+
+
+
+
+
+ {title}
+
+
+ {date}
+
+
+
+ {currencyFormat(sales)}
+
+
+
+ {`+${increment}%`} last month
+
+
+
+ );
+};
+
+export default SaleInfo;
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/SaleInfoSection/SaleInfoCards.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/SaleInfoSection/SaleInfoCards.tsx
new file mode 100644
index 0000000..bf8f76b
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/SaleInfoSection/SaleInfoCards.tsx
@@ -0,0 +1,22 @@
+import { Stack } from '@mui/material';
+import { saleInfoData } from 'data/sale-info-data';
+import SaleInfo from './SaleInfo';
+
+const SaleInfoCards = () => {
+ return (
+
+ {saleInfoData.map((saleInfoDataItem) => (
+
+ ))}
+
+ );
+};
+
+export default SaleInfoCards;
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/TopSellingProduct/CustomPagination.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/TopSellingProduct/CustomPagination.tsx
new file mode 100644
index 0000000..a7ea5c4
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/TopSellingProduct/CustomPagination.tsx
@@ -0,0 +1,80 @@
+import { PaginationItem, TablePaginationProps, Typography } from '@mui/material';
+import {
+ GridPagination,
+ gridExpandedRowCountSelector,
+ gridPageCountSelector,
+ gridPaginationRowRangeSelector,
+ useGridApiContext,
+ useGridSelector,
+} from '@mui/x-data-grid';
+import MuiPagination from '@mui/material/Pagination';
+import { useBreakpoints } from 'providers/BreakpointsProvider';
+
+function Pagination({
+ page,
+ className,
+}: Pick) {
+ const apiRef = useGridApiContext();
+ const { down } = useBreakpoints();
+ const belowSmallScreen = down('sm');
+
+ const pageCount = useGridSelector(apiRef, gridPageCountSelector);
+ const available = useGridSelector(apiRef, gridExpandedRowCountSelector);
+ const paginationRowRange = useGridSelector(apiRef, gridPaginationRowRangeSelector);
+
+ return (
+ <>
+ {pageCount !== 0 ? (
+
+ Showing {(paginationRowRange?.firstRowIndex as number) + 1} -{' '}
+ {(paginationRowRange?.lastRowIndex as number) + 1} of {available} Products
+
+ ) : (
+
+ Showing 0 - 0 of {available} Products
+
+ )}
+ apiRef.current.setPage(newPage - 1)}
+ renderItem={(item) => (
+ <>Prev>,
+ next: () => <>Next>,
+ }}
+ sx={(theme) => ({
+ '&.Mui-selected': {
+ color: theme.palette.common.white,
+ },
+ '&.Mui-disabled': {
+ color: theme.palette.text.secondary,
+ },
+ })}
+ />
+ )}
+ sx={{
+ mx: { xs: 'auto', sm: 'initial' },
+ }}
+ />
+ >
+ );
+}
+
+export default function CustomPagination(props: object) {
+ return ;
+}
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/TopSellingProduct/TopSellingProduct.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/TopSellingProduct/TopSellingProduct.tsx
new file mode 100644
index 0000000..5e30d76
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/TopSellingProduct/TopSellingProduct.tsx
@@ -0,0 +1,200 @@
+import { ChangeEvent, ReactElement, useMemo, useState } from 'react';
+import {
+ Avatar,
+ Divider,
+ InputAdornment,
+ LinearProgress,
+ Link,
+ Stack,
+ TextField,
+ Tooltip,
+ Typography,
+ debounce,
+} from '@mui/material';
+import { DataGrid, GridApi, GridColDef, GridSlots, useGridApiRef } from '@mui/x-data-grid';
+import IconifyIcon from 'components/base/IconifyIcon';
+import { DataRow, rows } from 'data/products';
+import CustomPagination from './CustomPagination';
+import { currencyFormat } from 'helpers/format-functions';
+
+const columns: GridColDef[] = [
+ {
+ field: 'id',
+ headerName: 'ID',
+ },
+ {
+ field: 'product',
+ headerName: 'Product',
+ flex: 1,
+ minWidth: 182.9625,
+ valueGetter: (params: any) => {
+ return params.title + ' ' + params.subtitle;
+ },
+ renderCell: (params: any) => {
+ return (
+
+
+
+
+
+
+ {params.row.product.title}
+
+
+ {params.row.product.subtitle}
+
+
+
+ );
+ },
+ sortComparator: (v1: string, v2: string) => v1.localeCompare(v2),
+ },
+ {
+ field: 'orders',
+ headerName: 'Orders',
+ flex: 0.75,
+ minWidth: 137.221875,
+ },
+ {
+ field: 'price',
+ headerName: 'Price',
+ flex: 0.75,
+ minWidth: 137.221875,
+ valueGetter: (params: any) => {
+ return currencyFormat(params);
+ },
+ },
+ {
+ field: 'adsSpent',
+ headerName: 'Ads Spent',
+ flex: 0.75,
+ minWidth: 137.221875,
+ valueGetter: (params: any) => {
+ return currencyFormat(params, { minimumFractionDigits: 3 });
+ },
+ },
+ {
+ field: 'refunds',
+ headerName: 'Refunds',
+ flex: 0.75,
+ minWidth: 137.221875,
+ renderCell: ({ row: { refunds } }: any) => {
+ if (refunds > 0) return `> ${refunds}`;
+ else return `< ${-refunds}`;
+ },
+ filterable: false,
+ },
+];
+
+const TopSellingProduct = (): ReactElement => {
+ const apiRef = useGridApiRef();
+ const [search, setSearch] = useState('');
+
+ const visibleColumns = useMemo(
+ () =>
+ columns
+ .filter((column) => column.field !== 'id')
+ .map((column) => {
+ if (column.field === 'refunds') {
+ return {
+ ...column,
+ getApplyQuickFilterFn: undefined,
+ filterable: false,
+ };
+ }
+ return column;
+ }),
+ [columns],
+ );
+
+ const handleGridSearch = useMemo(() => {
+ return debounce((searchValue) => {
+ apiRef.current.setQuickFilterValues(
+ searchValue.split(' ').filter((word: any) => word !== ''),
+ );
+ }, 250);
+ }, [apiRef]);
+
+ const handleChange = (event: ChangeEvent) => {
+ const searchValue = event.currentTarget.value;
+ setSearch(searchValue);
+ handleGridSearch(searchValue);
+ };
+
+ return (
+ theme.shadows[4]}
+ height={1}
+ >
+
+
+ Top Selling Product
+
+
+
+
+ ),
+ }}
+ />
+
+
+
+ 70}
+ hideFooterSelectedRowCount
+ disableColumnResize
+ disableColumnSelector
+ disableRowSelectionOnClick
+ rowSelection={false}
+ initialState={{
+ pagination: { paginationModel: { pageSize: 5, page: 0 } },
+ columns: {
+ columnVisibilityModel: {
+ id: false,
+ },
+ },
+ }}
+ pageSizeOptions={[5]}
+ onResize={() => {
+ apiRef.current.autosizeColumns({
+ includeOutliers: true,
+ expand: true,
+ });
+ }}
+ slots={{
+ loadingOverlay: LinearProgress as GridSlots['loadingOverlay'],
+ pagination: CustomPagination,
+ noRowsOverlay: () => ,
+ }}
+ sx={{
+ height: 1,
+ width: 1,
+ }}
+ />
+
+
+ );
+};
+
+export default TopSellingProduct;
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/WebsiteVisitors/WebsiteVisitors.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/WebsiteVisitors/WebsiteVisitors.tsx
new file mode 100644
index 0000000..34e9b77
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/WebsiteVisitors/WebsiteVisitors.tsx
@@ -0,0 +1,137 @@
+import { ReactElement, useMemo, useRef, useState } from 'react';
+import { Box, Button, Divider, Stack, Typography, useTheme } from '@mui/material';
+import EChartsReactCore from 'echarts-for-react/lib/core';
+import { PieDataItemOption } from 'echarts/types/src/chart/pie/PieSeries.js';
+import WebsiteVisitorsChart from './WebsiteVisitorsChart';
+
+const WebsiteVisitors = (): ReactElement => {
+ const theme = useTheme();
+
+ const seriesData: PieDataItemOption[] = [
+ { value: 6840, name: 'Direct' },
+ { value: 3960, name: 'Organic' },
+ { value: 2160, name: 'Paid' },
+ { value: 5040, name: 'Social' },
+ ];
+
+ const legendData = [
+ { name: 'Direct', icon: 'circle' },
+ { name: 'Organic', icon: 'circle' },
+ { name: 'Paid', icon: 'circle' },
+ { name: 'Social', icon: 'circle' },
+ ];
+
+ const pieChartColors = [
+ theme.palette.primary.main,
+ theme.palette.secondary.main,
+ theme.palette.info.main,
+ theme.palette.error.main,
+ ];
+
+ const chartRef = useRef(null);
+ const onChartLegendSelectChanged = (name: string) => {
+ if (chartRef.current) {
+ const instance = chartRef.current.getEchartsInstance();
+ instance.dispatchAction({
+ type: 'legendToggleSelect',
+ name: name,
+ });
+ }
+ };
+ const [visitorType, setVisitorType] = useState({
+ Direct: false,
+ Organic: false,
+ Paid: false,
+ Social: false,
+ });
+
+ const toggleClicked = (name: string) => {
+ setVisitorType((prevState: any) => ({
+ ...prevState,
+ [name]: !prevState[name],
+ }));
+ };
+ const totalVisitors = useMemo(
+ () => seriesData.reduce((acc: number, next: any) => acc + next.value, 0),
+ [],
+ );
+
+ return (
+
+
+ Website Visitors
+
+
+
+
+
+ }
+ sx={{ px: 2.5, py: 2.5 }}
+ justifyContent="center"
+ alignItems="stretch"
+ flex={'1 1 0%'}
+ >
+ {Array.isArray(seriesData) &&
+ seriesData.map((dataItem, index) => (
+ {
+ toggleClicked(dataItem.name as string);
+ onChartLegendSelectChanged(dataItem.name as string);
+ }}
+ sx={{
+ justifyContent: 'flex-start',
+ p: 0,
+ borderRadius: 1,
+ opacity: visitorType[`${dataItem.name}`] ? 0.5 : 1,
+ }}
+ disableRipple
+ >
+
+
+
+ {dataItem.name}
+
+
+ {((parseInt(`${dataItem.value}`) / totalVisitors) * 100).toFixed(0)}%
+
+
+
+ ))}
+
+
+
+ );
+};
+
+export default WebsiteVisitors;
diff --git a/ditch-the-agent/src/components/sections/dashboard/Home/Sales/WebsiteVisitors/WebsiteVisitorsChart.tsx b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/WebsiteVisitors/WebsiteVisitorsChart.tsx
new file mode 100644
index 0000000..19671e0
--- /dev/null
+++ b/ditch-the-agent/src/components/sections/dashboard/Home/Sales/WebsiteVisitors/WebsiteVisitorsChart.tsx
@@ -0,0 +1,72 @@
+import { SxProps, useTheme } from '@mui/material';
+import ReactEchart from 'components/base/ReactEchart';
+import * as echarts from 'echarts';
+import EChartsReactCore from 'echarts-for-react/lib/core';
+import { PieDataItemOption } from 'echarts/types/src/chart/pie/PieSeries.js';
+import { useMemo } from 'react';
+import { EChartsOption } from 'echarts-for-react';
+
+type WebsiteVisitorsChartProps = {
+ chartRef: React.MutableRefObject;
+ seriesData?: PieDataItemOption[];
+ legendData?: any;
+ colors?: string[];
+ sx?: SxProps;
+};
+
+const WebsiteVisitorsChart = ({
+ chartRef,
+ seriesData,
+ legendData,
+ colors,
+ ...rest
+}: WebsiteVisitorsChartProps) => {
+ const theme = useTheme();
+ const option: EChartsOption = useMemo(
+ () => ({
+ tooltip: {
+ trigger: 'item',
+ },
+ legend: {
+ show: false,
+ data: legendData,
+ },
+ series: [
+ {
+ name: 'Website Visitors',
+ type: 'pie',
+ radius: ['65%', '80%'],
+ avoidLabelOverlap: true,
+ startAngle: 0,
+ itemStyle: {
+ borderRadius: 10,
+ borderColor: theme.palette.common.white,
+ borderWidth: 2,
+ },
+ color: colors,
+ label: {
+ show: false,
+ position: 'center',
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: 30,
+ fontWeight: 'bold',
+ formatter: `{b}`,
+ },
+ },
+ labelLine: {
+ show: false,
+ },
+ data: seriesData,
+ },
+ ],
+ }),
+ [theme],
+ );
+
+ return ;
+};
+
+export default WebsiteVisitorsChart;
diff --git a/ditch-the-agent/src/contexts/AuthContext.tsx b/ditch-the-agent/src/contexts/AuthContext.tsx
new file mode 100644
index 0000000..7c256cb
--- /dev/null
+++ b/ditch-the-agent/src/contexts/AuthContext.tsx
@@ -0,0 +1,66 @@
+import { jwtDecode } from "jwt-decode";
+import { createContext, ReactNode, useState, useEffect } from "react"
+
+
+type AuthProviderProps = {
+ children?: ReactNode;
+}
+
+type IAuthContext = {
+ authenticated: boolean;
+ setAuthentication: (newState: boolean) => void;
+ needsNewPassword: boolean;
+ setNeedsNewPassword: (newState: boolean) => void;
+ loading: boolean;
+}
+
+const initialValues = {
+ authenticated: false,
+ setAuthentication: () => {},
+ needsNewPassword: false,
+ setNeedsNewPassword: () => {},
+ loading: true,
+}
+
+const AuthContext = createContext(initialValues);
+
+
+const AuthProvider = ({children}: AuthProviderProps) => {
+
+
+ const [ authenticated, setAuthentication ] = useState(initialValues.authenticated);
+ const [loading, setLoading] = useState(true); // Add a loading state
+
+ useEffect(() => {
+ console.log('we are in the auth provider')
+ const accessToken = localStorage.getItem('access_token');
+ if (accessToken) {
+ const decodedToken = jwtDecode(accessToken)
+ //console.log(decodedToken)
+ if(decodedToken.exp){
+ //console.log(decodedToken.exp * 1000)
+ //console.log(Date.now())
+ if (decodedToken.exp * 1000> Date.now()) {
+ console.log('We are setting that we are authenticated')
+ setAuthentication(true);
+ }
+
+ }
+
+ }
+ setLoading(false);
+
+
+ }, [])
+ //console.log(authenticated)
+ const [ needsNewPassword, setNeedsNewPassword] = useState(initialValues.needsNewPassword)
+
+
+ return (
+
+ {children}
+
+ )
+}
+
+export { AuthContext, AuthProvider }
\ No newline at end of file
diff --git a/ditch-the-agent/src/data/customers-list.ts b/ditch-the-agent/src/data/customers-list.ts
new file mode 100644
index 0000000..9696581
--- /dev/null
+++ b/ditch-the-agent/src/data/customers-list.ts
@@ -0,0 +1,38 @@
+import leatrice from 'assets/new-customers/leatrice.png';
+import roselle from 'assets/new-customers/roselle.jpg';
+import darron from 'assets/new-customers/darron.png';
+import jone from 'assets/new-customers/jone.png';
+
+interface CustomerData {
+ id: number;
+ name: string;
+ country: string;
+ avatar: string;
+}
+
+export const customerList: CustomerData[] = [
+ {
+ id: 1,
+ name: 'Roselle Ehrman',
+ country: 'Brazil',
+ avatar: roselle,
+ },
+ {
+ id: 2,
+ name: 'Jone Smith',
+ country: 'Australia',
+ avatar: jone,
+ },
+ {
+ id: 3,
+ name: 'Darron Handler',
+ country: 'Pakistan',
+ avatar: darron,
+ },
+ {
+ id: 4,
+ name: 'Leatrice Kulik',
+ country: 'Mascow',
+ avatar: leatrice,
+ },
+];
diff --git a/ditch-the-agent/src/data/nav-items.ts b/ditch-the-agent/src/data/nav-items.ts
new file mode 100644
index 0000000..0f87e17
--- /dev/null
+++ b/ditch-the-agent/src/data/nav-items.ts
@@ -0,0 +1,111 @@
+export interface NavItem {
+ title: string;
+ path: string;
+ icon?: string;
+ active: boolean;
+ collapsible: boolean;
+ sublist?: NavItem[];
+}
+
+const navItems: NavItem[] = [
+ {
+ title: 'Home',
+ path: '/',
+ icon: 'ion:home-sharp',
+ active: true,
+ collapsible: false,
+ sublist: [
+ {
+ title: 'Dashboard',
+ path: '/',
+ active: false,
+ collapsible: false,
+ },
+ {
+ title: 'Sales',
+ path: '/',
+ active: false,
+ collapsible: false,
+ },
+ ],
+ },
+ {
+ title: 'Authentication',
+ path: 'authentication',
+ icon: 'f7:exclamationmark-shield-fill',
+ active: true,
+ collapsible: true,
+ sublist: [
+ {
+ title: 'Sign In',
+ path: 'login',
+ active: true,
+ collapsible: false,
+ },
+ {
+ title: 'Sign Up',
+ path: 'sign-up',
+ active: true,
+ collapsible: false,
+ },
+ {
+ title: 'Forgot password',
+ path: 'forgot-password',
+ active: true,
+ collapsible: false,
+ },
+ {
+ title: 'Reset password',
+ path: 'reset-password',
+ active: true,
+ collapsible: false,
+ },
+ ],
+ },
+ {
+ title: 'Notification',
+ path: '#!',
+ icon: 'zondicons:notifications',
+ active: false,
+ collapsible: false,
+ },
+ {
+ title: 'Calendar',
+ path: '#!',
+ icon: 'ph:calendar',
+ active: false,
+ collapsible: false,
+ },
+ {
+ title: 'Message',
+ path: '#!',
+ icon: 'ph:chat-circle-dots-fill',
+ active: false,
+ collapsible: false,
+ },
+
+ {
+ title: 'Property',
+ path: '/property',
+ icon: 'ph:house-line',
+ active: true,
+ collapsible: false,
+ },
+ {
+ title: 'Education',
+ path: '/education',
+ icon: 'ph:student',
+ active: true,
+ collapsible: false,
+ },
+ {
+ title: 'Vendors',
+ path: '/vendors',
+ icon: 'ph:toolbox',
+ active: true,
+ collapsible: false,
+ },
+
+];
+
+export default navItems;
diff --git a/ditch-the-agent/src/data/products.ts b/ditch-the-agent/src/data/products.ts
new file mode 100644
index 0000000..4d4da60
--- /dev/null
+++ b/ditch-the-agent/src/data/products.ts
@@ -0,0 +1,141 @@
+import relaxingChair from 'assets/top-selling-products/relaxingChair.jpg';
+import instaxCamera from 'assets/top-selling-products/instaxCamera.jpg';
+import nikeV22 from 'assets/top-selling-products/nikeV22.jpg';
+import laptop from 'assets/top-selling-products/laptop.jpg';
+import watch from 'assets/top-selling-products/watch.jpg';
+
+export interface DataRow {
+ id: number;
+ product: {
+ avatar: string;
+ title: string;
+ subtitle: string;
+ };
+ orders: number;
+ price: number;
+ adsSpent: number;
+ refunds: number;
+}
+
+export const rows: DataRow[] = [
+ {
+ id: 1,
+ product: {
+ avatar: nikeV22,
+ title: 'Nike v22',
+ subtitle: 'Running Shoes',
+ },
+ orders: 8000,
+ price: 130,
+ adsSpent: 9.5,
+ refunds: 13,
+ },
+ {
+ id: 2,
+ product: {
+ avatar: instaxCamera,
+ title: 'Instax Camera',
+ subtitle: 'Portable Camera',
+ },
+ orders: 3000,
+ price: 45,
+ adsSpent: 4.5,
+ refunds: 18,
+ },
+ {
+ id: 3,
+ product: {
+ avatar: relaxingChair,
+ title: 'Chair ',
+ subtitle: 'Relaxing chair',
+ },
+ orders: 6000,
+ price: 80,
+ adsSpent: 5.8,
+ refunds: -11,
+ },
+ {
+ id: 4,
+ product: {
+ avatar: laptop,
+ title: 'Laptop',
+ subtitle: 'Macbook pro 13',
+ },
+ orders: 4000,
+ price: 500,
+ adsSpent: 4.7,
+ refunds: 18,
+ },
+ {
+ id: 5,
+ product: {
+ avatar: watch,
+ title: 'Watch',
+ subtitle: 'Digital watch',
+ },
+ orders: 2000,
+ price: 15,
+ adsSpent: 2.5,
+ refunds: -10,
+ },
+ {
+ id: 6,
+ product: {
+ avatar: relaxingChair,
+ title: 'Chair',
+ subtitle: 'Relaxing chair',
+ },
+ orders: 6000,
+ price: 80,
+ adsSpent: 5.8,
+ refunds: -11,
+ },
+ {
+ id: 7,
+ product: {
+ avatar: instaxCamera,
+ title: 'Instax Camera',
+ subtitle: 'Portable Camera',
+ },
+ orders: 3000,
+ price: 45,
+ adsSpent: 4.5,
+ refunds: 18,
+ },
+ {
+ id: 8,
+ product: {
+ avatar: watch,
+ title: 'Watch',
+ subtitle: 'Digital watch',
+ },
+ orders: 2000,
+ price: 15,
+ adsSpent: 2.5,
+ refunds: -10,
+ },
+ {
+ id: 9,
+ product: {
+ avatar: nikeV22,
+ title: 'Nike v22',
+ subtitle: 'Running Shoes',
+ },
+ orders: 8000,
+ price: 130,
+ adsSpent: 9.5,
+ refunds: 13,
+ },
+ {
+ id: 10,
+ product: {
+ avatar: laptop,
+ title: 'Laptop',
+ subtitle: 'Macbook pro 13',
+ },
+ orders: 4000,
+ price: 500,
+ adsSpent: 4.7,
+ refunds: 18,
+ },
+];
diff --git a/ditch-the-agent/src/data/sale-info-data.ts b/ditch-the-agent/src/data/sale-info-data.ts
new file mode 100644
index 0000000..e030437
--- /dev/null
+++ b/ditch-the-agent/src/data/sale-info-data.ts
@@ -0,0 +1,39 @@
+import avgRevenue from 'assets/sale-info/avg-revenue.png';
+import customers from 'assets/sale-info/customers.png';
+import sales from 'assets/sale-info/sales.png';
+
+interface SaleInfoData {
+ id: number;
+ image: string;
+ title: string;
+ sales: number;
+ increment: number;
+ date: string;
+}
+
+export const saleInfoData: SaleInfoData[] = [
+ {
+ id: 1,
+ image: sales,
+ title: 'Sales',
+ sales: 230220,
+ increment: 55,
+ date: 'May 2022',
+ },
+ {
+ id: 2,
+ image: customers,
+ title: 'Customers',
+ sales: 3200,
+ increment: 12,
+ date: 'May 2022',
+ },
+ {
+ id: 3,
+ image: avgRevenue,
+ title: 'Avg Revenue',
+ sales: 2300,
+ increment: 210,
+ date: 'May 2022',
+ },
+];
diff --git a/ditch-the-agent/src/helpers/capitalize-pathname.ts b/ditch-the-agent/src/helpers/capitalize-pathname.ts
new file mode 100644
index 0000000..4f7fabf
--- /dev/null
+++ b/ditch-the-agent/src/helpers/capitalize-pathname.ts
@@ -0,0 +1,12 @@
+function capitalizePathname(input: string): string {
+ const lastSegment = input.split('/').at(-1);
+
+ if (lastSegment) {
+ return lastSegment
+ .split('-')
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
+ .join(' ');
+ } else return '';
+}
+
+export default capitalizePathname;
diff --git a/ditch-the-agent/src/helpers/format-functions.ts b/ditch-the-agent/src/helpers/format-functions.ts
new file mode 100644
index 0000000..4751f34
--- /dev/null
+++ b/ditch-the-agent/src/helpers/format-functions.ts
@@ -0,0 +1,11 @@
+export const currencyFormat = (amount: number, options: Intl.NumberFormatOptions = {}) => {
+ return new Intl.NumberFormat('en-US', {
+ style: 'currency',
+ currency: 'usd',
+ maximumFractionDigits: 3,
+ minimumFractionDigits: 0,
+ useGrouping: true,
+ notation: 'standard',
+ ...options,
+ }).format(amount);
+};
diff --git a/ditch-the-agent/src/index.css b/ditch-the-agent/src/index.css
new file mode 100644
index 0000000..a4ff553
--- /dev/null
+++ b/ditch-the-agent/src/index.css
@@ -0,0 +1,5 @@
+@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;700&family=Poppins:wght@400;500;600;700&display=swap');
+
+html {
+ scroll-behavior: smooth;
+}
diff --git a/ditch-the-agent/src/layouts/auth-layout/index.tsx b/ditch-the-agent/src/layouts/auth-layout/index.tsx
new file mode 100644
index 0000000..5c76f19
--- /dev/null
+++ b/ditch-the-agent/src/layouts/auth-layout/index.tsx
@@ -0,0 +1,19 @@
+import { PropsWithChildren, ReactElement } from 'react';
+import { Stack } from '@mui/material';
+
+const AuthLayout = ({ children }: PropsWithChildren): ReactElement => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default AuthLayout;
diff --git a/ditch-the-agent/src/layouts/main-layout/Footer.tsx b/ditch-the-agent/src/layouts/main-layout/Footer.tsx
new file mode 100644
index 0000000..75265ce
--- /dev/null
+++ b/ditch-the-agent/src/layouts/main-layout/Footer.tsx
@@ -0,0 +1,26 @@
+import { Link, Stack, Typography } from '@mui/material';
+
+const Footer = () => {
+ return (
+
+
+
+ Ditch The Agent
+
+
+
+ );
+};
+
+export default Footer;
diff --git a/ditch-the-agent/src/layouts/main-layout/Sidebar/NavButton.tsx b/ditch-the-agent/src/layouts/main-layout/Sidebar/NavButton.tsx
new file mode 100644
index 0000000..a1e12ad
--- /dev/null
+++ b/ditch-the-agent/src/layouts/main-layout/Sidebar/NavButton.tsx
@@ -0,0 +1,149 @@
+import { ReactElement, useState } from 'react';
+import {
+ Collapse,
+ LinkTypeMap,
+ List,
+ ListItem,
+ ListItemButton,
+ ListItemIcon,
+ ListItemText,
+} from '@mui/material';
+import { OverridableComponent } from '@mui/material/OverridableComponent';
+import IconifyIcon from 'components/base/IconifyIcon';
+import { useLocation } from 'react-router-dom';
+import { NavItem } from 'data/nav-items';
+
+interface NavItemProps {
+ navItem: NavItem;
+ Link: OverridableComponent;
+}
+
+const NavButton = ({ navItem, Link }: NavItemProps): ReactElement => {
+ const { pathname } = useLocation();
+ const [checked, setChecked] = useState(false);
+ const [nestedChecked, setNestedChecked] = useState([]);
+
+ const handleNestedChecked = (index: any, value: boolean) => {
+ const updatedBooleanArray = [...nestedChecked];
+ updatedBooleanArray[index] = value;
+ setNestedChecked(updatedBooleanArray);
+ };
+
+ return (
+
+ {navItem.collapsible ? (
+ <>
+ setChecked(!checked)}>
+
+
+
+ {navItem.title}
+
+ {navItem.collapsible &&
+ (checked ? (
+
+ ) : (
+
+ ))}
+
+
+
+
+ {navItem.sublist?.map((subListItem: any, idx: number) => (
+
+ {subListItem.collapsible ? (
+ <>
+ {
+ handleNestedChecked(idx, !nestedChecked[idx]);
+ }}
+ >
+ {subListItem.title}
+
+ {subListItem.collapsible &&
+ (nestedChecked[idx] ? (
+
+ ) : (
+
+ ))}
+
+
+
+
+ {subListItem?.sublist?.map(
+ (nestedSubListItem: any, nestedIdx: number) => (
+
+
+
+ {nestedSubListItem.title}
+
+
+
+ ),
+ )}
+
+
+ >
+ ) : (
+
+ {subListItem.title}
+
+ )}
+
+ ))}
+
+
+ >
+ ) : (
+
+
+
+
+ {navItem.title}
+
+ )}
+
+ );
+};
+
+export default NavButton;
diff --git a/ditch-the-agent/src/layouts/main-layout/Sidebar/Sidebar.tsx b/ditch-the-agent/src/layouts/main-layout/Sidebar/Sidebar.tsx
new file mode 100644
index 0000000..c6ca795
--- /dev/null
+++ b/ditch-the-agent/src/layouts/main-layout/Sidebar/Sidebar.tsx
@@ -0,0 +1,109 @@
+import { ReactElement } from 'react';
+import {
+ Link,
+ List,
+ ListItem,
+ ListItemButton,
+ ListItemIcon,
+ ListItemText,
+ Stack,
+} from '@mui/material';
+
+import IconifyIcon from 'components/base/IconifyIcon';
+import logo from 'assets/logo/favicon-logo.png';
+import Image from 'components/base/Image';
+import navItems from 'data/nav-items';
+import NavButton from './NavButton';
+
+const Sidebar = (): ReactElement => {
+ return (
+ theme.shadows[4]}
+ sx={{
+ overflow: 'hidden',
+ margin: { xs: 0, lg: 3.75 },
+ borderRadius: { xs: 0, lg: 5 },
+ '&:hover': {
+ overflowY: 'auto',
+ },
+ width: 218,
+ }}
+ >
+
+
+
+
+
+ {navItems.map((navItem, index) => (
+
+ ))}
+
+
+
+
+
+
+
+ Log out
+
+
+
+
+
+ );
+};
+
+export default Sidebar;
diff --git a/ditch-the-agent/src/layouts/main-layout/Topbar/AccountDropdown.tsx b/ditch-the-agent/src/layouts/main-layout/Topbar/AccountDropdown.tsx
new file mode 100644
index 0000000..62e6e35
--- /dev/null
+++ b/ditch-the-agent/src/layouts/main-layout/Topbar/AccountDropdown.tsx
@@ -0,0 +1,146 @@
+import {
+ Avatar,
+ Button,
+ Divider,
+ ListItemIcon,
+ ListItemText,
+ Menu,
+ MenuItem,
+ Tooltip,
+ Typography,
+} from '@mui/material';
+import IconifyIcon from 'components/base/IconifyIcon';
+import { MouseEvent, ReactElement, useState } from 'react';
+import profile from 'assets/profile/profile.jpg';
+
+const AccountDropdown = (): ReactElement => {
+ const [anchorEl, setAnchorEl] = useState(null);
+ const open = Boolean(anchorEl);
+ const handleClick = (event: MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+ return (
+ <>
+
+
+
+
+
+ Aiden Max
+
+
+
+
+ >
+ );
+};
+
+export default AccountDropdown;
diff --git a/ditch-the-agent/src/layouts/main-layout/Topbar/LanguageDropdown.tsx b/ditch-the-agent/src/layouts/main-layout/Topbar/LanguageDropdown.tsx
new file mode 100644
index 0000000..f02b782
--- /dev/null
+++ b/ditch-the-agent/src/layouts/main-layout/Topbar/LanguageDropdown.tsx
@@ -0,0 +1,126 @@
+import {
+ IconButton,
+ ListItemIcon,
+ ListItemText,
+ Menu,
+ MenuItem,
+ Stack,
+ Typography,
+} from '@mui/material';
+import IconifyIcon from 'components/base/IconifyIcon';
+import { MouseEvent, ReactElement, useState } from 'react';
+
+interface Language {
+ id: number;
+ value: string;
+ label: string;
+ icon: string;
+}
+
+const languages: Language[] = [
+ {
+ id: 0,
+ value: 'eng',
+ label: 'English',
+ icon: 'twemoji:flag-united-kingdom',
+ },
+ {
+ id: 1,
+ value: 'fr',
+ label: 'Française',
+ icon: 'twemoji:flag-france',
+ },
+ {
+ id: 2,
+ value: 'ban',
+ label: 'বাংলা',
+ icon: 'twemoji:flag-bangladesh',
+ },
+ {
+ id: 3,
+ value: 'zho',
+ label: '官话',
+ icon: 'twemoji:flag-china',
+ },
+ {
+ id: 4,
+ value: 'hin',
+ label: 'हिन्दी',
+ icon: 'twemoji:flag-india',
+ },
+ {
+ id: 5,
+ value: 'ara',
+ label: 'Arabic',
+ icon: 'twemoji:flag-saudi-arabia',
+ },
+];
+
+const LanguageDropdown = (): ReactElement => {
+ const [anchorEl, setAnchorEl] = useState(null);
+ const [selectedIndex, setSelectedIndex] = useState(0);
+ const open = Boolean(anchorEl);
+
+ const handleClickItem = (event: MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleMenuItemClick = (id: number) => {
+ setSelectedIndex(id);
+ setAnchorEl(null);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+ return (
+ <>
+
+
+ >
+ );
+};
+
+export default LanguageDropdown;
diff --git a/ditch-the-agent/src/layouts/main-layout/Topbar/Topbar.tsx b/ditch-the-agent/src/layouts/main-layout/Topbar/Topbar.tsx
new file mode 100644
index 0000000..1f5769b
--- /dev/null
+++ b/ditch-the-agent/src/layouts/main-layout/Topbar/Topbar.tsx
@@ -0,0 +1,117 @@
+import { MouseEventHandler, ReactElement } from 'react';
+import {
+ AppBar,
+ Badge,
+ IconButton,
+ InputAdornment,
+ Link,
+ Stack,
+ TextField,
+ Toolbar,
+ Typography,
+} from '@mui/material';
+import IconifyIcon from 'components/base/IconifyIcon';
+import { drawerWidth } from 'layouts/main-layout';
+
+import { useLocation } from 'react-router-dom';
+import capitalizePathname from 'helpers/capitalize-pathname';
+import AccountDropdown from './AccountDropdown';
+import LanguageDropdown from './LanguageDropdown';
+import Image from 'components/base/Image';
+import logo from 'assets/logo/favicon-logo.png';
+
+interface TopbarProps {
+ handleDrawerToggle: MouseEventHandler;
+}
+
+const Topbar = ({ handleDrawerToggle }: TopbarProps): ReactElement => {
+ const { pathname } = useLocation();
+ const title = capitalizePathname(pathname);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {pathname === '/' ? 'Dashboard' : title}
+
+
+
+
+ ),
+ }}
+ fullWidth
+ sx={{ maxWidth: 330 }}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Topbar;
diff --git a/ditch-the-agent/src/layouts/main-layout/index.tsx b/ditch-the-agent/src/layouts/main-layout/index.tsx
new file mode 100644
index 0000000..7fbbaf2
--- /dev/null
+++ b/ditch-the-agent/src/layouts/main-layout/index.tsx
@@ -0,0 +1,93 @@
+import { PropsWithChildren, ReactElement, useState } from 'react';
+import { Box, Drawer, Stack, Toolbar } from '@mui/material';
+
+
+
+import Sidebar from 'layouts/main-layout/Sidebar/Sidebar';
+import Topbar from 'layouts/main-layout/Topbar/Topbar';
+import Footer from './Footer';
+import FloatingChatButton from 'components/FloatingChatButton';
+
+export const drawerWidth = 278;
+
+const MainLayout = ({ children }: PropsWithChildren): ReactElement => {
+ const [mobileOpen, setMobileOpen] = useState(false);
+ const [isClosing, setIsClosing] = useState(false);
+
+ const handleDrawerClose = () => {
+ setIsClosing(true);
+ setMobileOpen(false);
+ };
+
+ const handleDrawerTransitionEnd = () => {
+ setIsClosing(false);
+ };
+
+ const handleDrawerToggle = () => {
+ if (!isClosing) {
+ setMobileOpen(!mobileOpen);
+ }
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+ >
+ );
+};
+
+export default MainLayout;
diff --git a/ditch-the-agent/src/main.tsx b/ditch-the-agent/src/main.tsx
new file mode 100644
index 0000000..b06da31
--- /dev/null
+++ b/ditch-the-agent/src/main.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import './index.css';
+import { RouterProvider } from 'react-router-dom';
+import { theme } from './theme/theme.ts';
+import { CssBaseline, ThemeProvider } from '@mui/material';
+import BreakpointsProvider from 'providers/BreakpointsProvider.tsx';
+import router from 'routes/router.tsx';
+import { AuthProvider } from 'contexts/AuthContext.tsx';
+
+ReactDOM.createRoot(document.getElementById('root')!).render(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+);
diff --git a/ditch-the-agent/src/pages/Education/Education.tsx b/ditch-the-agent/src/pages/Education/Education.tsx
new file mode 100644
index 0000000..bad6f88
--- /dev/null
+++ b/ditch-the-agent/src/pages/Education/Education.tsx
@@ -0,0 +1,29 @@
+import { ReactElement } from 'react';
+import { drawerWidth } from 'layouts/main-layout';
+import Grid from '@mui/material/Unstable_Grid2';
+import { EducationInfoCards } from 'components/sections/dashboard/Home/Education/EducationInfo';
+
+const Education = (): ReactElement => {
+ return(
+
+
+
+
+
+ )
+}
+
+export default Education;
\ No newline at end of file
diff --git a/ditch-the-agent/src/pages/Property/Property.tsx b/ditch-the-agent/src/pages/Property/Property.tsx
new file mode 100644
index 0000000..0498a45
--- /dev/null
+++ b/ditch-the-agent/src/pages/Property/Property.tsx
@@ -0,0 +1,60 @@
+import { ReactElement } from 'react';
+import { drawerWidth } from 'layouts/main-layout';
+import Grid from '@mui/material/Unstable_Grid2';
+import PropertyDetailsCard from 'components/sections/dashboard/Home/Property/PropertyDetailsCard';
+import HomePriceEstimate from 'components/sections/dashboard/Home/Property/HomePriceEstimate';
+import PhotoGalleryCard from 'components/sections/dashboard/Home/Property/PhotoGalleryCard';
+import MarketStatistics from 'components/sections/dashboard/Home/Property/MarketStatistics';
+import PropertyListingCard from 'components/sections/dashboard/Home/Property/PropertyListingCard';
+import LoanDetailsCard from 'components/sections/dashboard/Home/Property/LoanDetailsCard';
+import PropertyValueGraphCard from 'components/sections/dashboard/Home/Property/PropertyValueGraphCard';
+
+const Property = (): ReactElement => {
+ return(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Property;
\ No newline at end of file
diff --git a/ditch-the-agent/src/pages/Vendors/Vendors.tsx b/ditch-the-agent/src/pages/Vendors/Vendors.tsx
new file mode 100644
index 0000000..b58b512
--- /dev/null
+++ b/ditch-the-agent/src/pages/Vendors/Vendors.tsx
@@ -0,0 +1,26 @@
+import { ReactElement } from 'react';
+import { drawerWidth } from 'layouts/main-layout';
+import Grid from '@mui/material/Unstable_Grid2';
+
+const Vendors = (): ReactElement => {
+ return(
+
+ Vendors
+
+ )
+}
+
+export default Vendors;
\ No newline at end of file
diff --git a/ditch-the-agent/src/pages/authentication/ForgotPassword.tsx b/ditch-the-agent/src/pages/authentication/ForgotPassword.tsx
new file mode 100644
index 0000000..99f03e6
--- /dev/null
+++ b/ditch-the-agent/src/pages/authentication/ForgotPassword.tsx
@@ -0,0 +1,82 @@
+import {
+ Button,
+ FormControl,
+ InputAdornment,
+ InputLabel,
+ Link,
+ Skeleton,
+ Stack,
+ TextField,
+ Typography,
+} from '@mui/material';
+import Image from 'components/base/Image';
+import { Suspense } from 'react';
+import forgotPassword from 'assets/authentication-banners/green.png';
+import IconifyIcon from 'components/base/IconifyIcon';
+import logo from 'assets/logo/favicon-logo.png';
+
+const ForgotPassword = () => {
+ return (
+ theme.shadows[3]}
+ height={560}
+ width={{ md: 960 }}
+ >
+
+
+
+
+
+ Forgot Password
+
+
+ Email
+
+
+
+
+ ),
+ }}
+ />
+
+
+ Send Password Reset Link
+
+
+ Back to{' '}
+ theme.typography.body1.fontSize}
+ >
+ Log in
+
+
+
+
+
+ }
+ >
+
+
+
+ );
+};
+
+export default ForgotPassword;
diff --git a/ditch-the-agent/src/pages/authentication/Login.tsx b/ditch-the-agent/src/pages/authentication/Login.tsx
new file mode 100644
index 0000000..6e82225
--- /dev/null
+++ b/ditch-the-agent/src/pages/authentication/Login.tsx
@@ -0,0 +1,129 @@
+import { ReactElement, Suspense, useState } from 'react';
+import {
+ Button,
+ FormControl,
+ IconButton,
+ InputAdornment,
+ InputLabel,
+ Link,
+ Skeleton,
+ Stack,
+ TextField,
+ Typography,
+} from '@mui/material';
+import loginBanner from 'assets/authentication-banners/green.png';
+import IconifyIcon from 'components/base/IconifyIcon';
+import logo from 'assets/logo/favicon-logo.png';
+import Image from 'components/base/Image';
+
+const Login = (): ReactElement => {
+ const [showPassword, setShowPassword] = useState(false);
+
+ const handleClickShowPassword = () => setShowPassword(!showPassword);
+
+ return (
+ theme.shadows[3]}
+ height={560}
+ width={{ md: 960 }}
+ >
+
+
+
+
+
+ Login
+
+
+ Email
+
+
+
+
+ ),
+ }}
+ />
+
+
+
+ Password
+
+
+
+ {showPassword ? (
+
+ ) : (
+
+ )}
+
+
+ ),
+ }}
+ />
+
+
+
+ Forget password
+
+
+
+ Log in
+
+
+ Don't have an account ?{' '}
+ theme.typography.body1.fontSize}
+ >
+ Sign up
+
+
+
+
+
+ }
+ >
+
+
+
+ );
+};
+
+export default Login;
diff --git a/ditch-the-agent/src/pages/authentication/ResetPassword.tsx b/ditch-the-agent/src/pages/authentication/ResetPassword.tsx
new file mode 100644
index 0000000..f1e1e50
--- /dev/null
+++ b/ditch-the-agent/src/pages/authentication/ResetPassword.tsx
@@ -0,0 +1,166 @@
+import { ReactElement, Suspense, useState } from 'react';
+import {
+ Button,
+ FormControl,
+ IconButton,
+ InputAdornment,
+ InputLabel,
+ Link,
+ Skeleton,
+ Stack,
+ TextField,
+ Typography,
+} from '@mui/material';
+import logo from 'assets/logo/favicon-logo.png';
+import resetPassword from 'assets/authentication-banners/green.png';
+import passwordUpdated from 'assets/authentication-banners/password-updated.png';
+import successTick from 'assets/authentication-banners/successTick.png';
+import Image from 'components/base/Image';
+import IconifyIcon from 'components/base/IconifyIcon';
+
+const ResetPassword = (): ReactElement => {
+ const [showNewPassword, setShowNewPassword] = useState(false);
+ const [showConfirmPassword, setShowConfirmPassword] = useState(false);
+
+ const handleClickShowNewPassword = () => setShowNewPassword(!showNewPassword);
+ const handleClickShowConfirmPassword = () => setShowConfirmPassword(!showConfirmPassword);
+ const [resetSuccessful, setResetSuccessful] = useState(false);
+
+ const handleResetPassword = () => {
+ const passwordField: HTMLInputElement = document.getElementById(
+ 'new-password',
+ ) as HTMLInputElement;
+ const confirmPasswordField: HTMLInputElement = document.getElementById(
+ 'confirm-password',
+ ) as HTMLInputElement;
+
+ if (passwordField.value !== confirmPasswordField.value) {
+ alert("Passwords don't match");
+ return;
+ }
+ setResetSuccessful(true);
+ };
+
+ return (
+ theme.shadows[3]}
+ height={560}
+ width={{ md: 960 }}
+ >
+
+
+
+
+ {!resetSuccessful ? (
+
+ Reset Password
+
+
+ Password
+
+
+
+ {showNewPassword ? (
+
+ ) : (
+
+ )}
+
+
+ ),
+ }}
+ />
+
+
+
+ Password
+
+
+
+ {showConfirmPassword ? (
+
+ ) : (
+
+ )}
+
+
+ ),
+ }}
+ />
+
+
+ Reset Password
+
+
+ Back to{' '}
+ theme.typography.body1.fontSize}
+ >
+ Log in
+
+
+
+ ) : (
+
+
+ Reset Successfully
+
+ Your Ditch the Agent log in password has been updated successfully
+
+
+ Continue to Login
+
+
+ )}
+
+
+ }
+ >
+
+
+
+ );
+};
+
+export default ResetPassword;
diff --git a/ditch-the-agent/src/pages/authentication/SignUp.tsx b/ditch-the-agent/src/pages/authentication/SignUp.tsx
new file mode 100644
index 0000000..5628356
--- /dev/null
+++ b/ditch-the-agent/src/pages/authentication/SignUp.tsx
@@ -0,0 +1,270 @@
+import { ReactElement, Suspense, useState } from 'react';
+import { Form, Formik } from 'formik';
+import {
+ Button,
+ FormControl,
+ FormControlLabel,
+ IconButton,
+ InputAdornment,
+ InputLabel,
+ Link,
+ OutlinedInput,
+ Radio,
+ RadioGroup,
+ Skeleton,
+ Stack,
+ TextField,
+ Typography,
+} from '@mui/material';
+import signupBanner from 'assets/authentication-banners/green.png';
+import IconifyIcon from 'components/base/IconifyIcon';
+import logo from 'assets/logo/favicon-logo.png';
+import Image from 'components/base/Image';
+import{axiosInstance} from '../../axiosApi.js';
+
+type SignUpValues = {
+ email: string;
+ first_name: string;
+ last_name: string;
+ password: string;
+ password2: string;
+ ownerType: string;
+}
+
+const SignUp = (): ReactElement => {
+ const [showPassword, setShowPassword] = useState(false);
+ const [showPassword2, setShowPassword2] = useState(false);
+
+ // const [firstName, setFirstName] = useState('');
+ // const [lastName, setLastName] = useState('');
+ // const [email, setEmail] = useState('');
+ // const [password, setPassword] = useState('');
+ // const [password2, setPassword2] = useState('');
+ // const [ownerType, setOwnerType] = useState('');
+
+ const handleClickShowPassword = () => setShowPassword(!showPassword);
+ const handleClickShowPassword2 = () => setShowPassword2(!showPassword2);
+
+ const handleSignUp = async({email, first_name, last_name, ownerType, password, password2}: SignUpValues): Promise => {
+
+ console.log({
+ email: email,
+ first_name: first_name,
+ last_name: last_name,
+ user_type: ownerType,
+ password: password,
+ password2: password2
+ })
+ const response = await axiosInstance.post('/api/register',
+ {
+ email: email,
+ first_name: first_name,
+ last_name: last_name,
+ user_type: ownerType,
+ password: password,
+ password2: password2
+ }
+ )
+ }
+ return (
+ theme.shadows[3]}
+
+ width={{ md: 960 }}
+ >
+
+
+
+
+
+ Signup
+
+ {(formik) => (
+
+
+ )}
+
+
+
+
+ Already have an account ?{' '}
+ theme.typography.body1.fontSize}
+ >
+ Log in
+
+
+
+
+
+ }
+ >
+
+
+
+ );
+};
+
+export default SignUp;
diff --git a/ditch-the-agent/src/pages/errors/Error404.tsx b/ditch-the-agent/src/pages/errors/Error404.tsx
new file mode 100644
index 0000000..7865648
--- /dev/null
+++ b/ditch-the-agent/src/pages/errors/Error404.tsx
@@ -0,0 +1,61 @@
+import { ReactElement } from 'react';
+import { Box, Button, Container, Stack, Typography } from '@mui/material';
+import { Link as Nav } from 'react-router-dom';
+import logo from 'assets/logo/favicon-logo.png';
+import Image from 'components/base/Image';
+
+import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
+
+const Error404 = (): ReactElement => {
+ const renderHeader: ReactElement = (
+
+
+
+ );
+ return (
+ <>
+ {renderHeader}
+
+
+
+ Sorry, page not found!
+
+
+ Sorry, we couldn’t find the page you’re looking for. Perhaps you’ve mistyped the URL? Be
+ sure to check your spelling.
+
+
+
+ Back to Home
+
+
+
+ >
+ );
+};
+
+export default Error404;
diff --git a/ditch-the-agent/src/pages/home/Sales.tsx b/ditch-the-agent/src/pages/home/Sales.tsx
new file mode 100644
index 0000000..4a4c729
--- /dev/null
+++ b/ditch-the-agent/src/pages/home/Sales.tsx
@@ -0,0 +1,65 @@
+import Grid from '@mui/material/Unstable_Grid2';
+import { Stack } from '@mui/material';
+import { ReactElement } from 'react';
+
+import TopSellingProduct from 'components/sections/dashboard/Home/Sales/TopSellingProduct/TopSellingProduct';
+import WebsiteVisitors from 'components/sections/dashboard/Home/Sales/WebsiteVisitors/WebsiteVisitors';
+import SaleInfoCards from 'components/sections/dashboard/Home/Sales/SaleInfoSection/SaleInfoCards';
+import BuyersProfile from 'components/sections/dashboard/Home/Sales/BuyersProfile/BuyersProfile';
+import NewCustomers from 'components/sections/dashboard/Home/Sales/NewCustomers/NewCustomers';
+import Revenue from 'components/sections/dashboard/Home/Sales/Revenue/Revenue';
+
+import { drawerWidth } from 'layouts/main-layout';
+import {EducationInfoCards} from 'components/sections/dashboard/Home/Education/EducationInfo';
+import { ProperyInfoCards } from 'components/sections/dashboard/Home/Property/PropertyInfo';
+
+const Sales = (): ReactElement => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Sales;
diff --git a/ditch-the-agent/src/pages/home/TermsOfService.tsx b/ditch-the-agent/src/pages/home/TermsOfService.tsx
new file mode 100644
index 0000000..c7fa230
--- /dev/null
+++ b/ditch-the-agent/src/pages/home/TermsOfService.tsx
@@ -0,0 +1,129 @@
+import { ReactElement, Suspense, useState } from 'react';
+import {
+ Button,
+ FormControl,
+ IconButton,
+ InputAdornment,
+ InputLabel,
+ Link,
+ Skeleton,
+ Stack,
+ TextField,
+ Typography,
+} from '@mui/material';
+import loginBanner from 'assets/authentication-banners/green.png';
+import IconifyIcon from 'components/base/IconifyIcon';
+import logo from 'assets/logo/favicon-logo.png';
+import Image from 'components/base/Image';
+
+const Login = (): ReactElement => {
+ const [showPassword, setShowPassword] = useState(false);
+
+ const handleClickShowPassword = () => setShowPassword(!showPassword);
+
+ return (
+ theme.shadows[3]}
+ height={560}
+ width={{ md: 960 }}
+ >
+
+
+
+
+
+ Login
+
+
+ Email
+
+
+
+
+ ),
+ }}
+ />
+
+
+
+ Password
+
+
+
+ {showPassword ? (
+
+ ) : (
+
+ )}
+
+
+ ),
+ }}
+ />
+
+
+
+ Forget password
+
+
+
+ Log in
+
+
+ Don't have an account ?{' '}
+ theme.typography.body1.fontSize}
+ >
+ Sign up
+
+
+
+
+
+ }
+ >
+
+
+
+ );
+};
+
+export default Login;
diff --git a/ditch-the-agent/src/providers/BreakpointsProvider.tsx b/ditch-the-agent/src/providers/BreakpointsProvider.tsx
new file mode 100644
index 0000000..ad0b5da
--- /dev/null
+++ b/ditch-the-agent/src/providers/BreakpointsProvider.tsx
@@ -0,0 +1,62 @@
+import { createContext, PropsWithChildren, useContext, useEffect, useState } from 'react';
+import { Breakpoint, Theme } from '@mui/material';
+import { useMediaQuery } from '@mui/material';
+
+interface BreakpointContextInterface {
+ currentBreakpoint: Breakpoint;
+ up: (key: Breakpoint | number) => boolean;
+ down: (key: Breakpoint | number) => boolean;
+ only: (key: Breakpoint | number) => boolean;
+ between: (start: Breakpoint | number, end: Breakpoint | number) => boolean;
+}
+
+export const BreakpointContext = createContext({} as BreakpointContextInterface);
+
+const BreakpointsProvider = ({ children }: PropsWithChildren) => {
+ const [currentBreakpoint, setCurrentBreakpoint] = useState('xs');
+ const up = (key: Breakpoint | number) =>
+ useMediaQuery((theme) => theme.breakpoints.up(key));
+
+ const down = (key: Breakpoint | number) =>
+ useMediaQuery((theme) => theme.breakpoints.down(key));
+
+ const only = (key: Breakpoint | number) =>
+ useMediaQuery((theme) => theme.breakpoints.only(key as Breakpoint));
+
+ const between = (start: Breakpoint | number, end: Breakpoint | number) =>
+ useMediaQuery((theme) => theme.breakpoints.between(start, end));
+
+ const isXs = between('xs', 'sm');
+ const isSm = between('sm', 'md');
+ const isMd = between('md', 'lg');
+ const isLg = between('lg', 'xl');
+ const isXl = up('xl');
+
+ useEffect(() => {
+ if (isXs) {
+ setCurrentBreakpoint('xs');
+ }
+ if (isSm) {
+ setCurrentBreakpoint('sm');
+ }
+ if (isMd) {
+ setCurrentBreakpoint('md');
+ }
+ if (isLg) {
+ setCurrentBreakpoint('lg');
+ }
+ if (isXl) {
+ setCurrentBreakpoint('xl');
+ }
+ }, [isXs, isSm, isMd, isLg, isXl]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useBreakpoints = () => useContext(BreakpointContext);
+
+export default BreakpointsProvider;
diff --git a/ditch-the-agent/src/routes/paths.ts b/ditch-the-agent/src/routes/paths.ts
new file mode 100644
index 0000000..0048ec9
--- /dev/null
+++ b/ditch-the-agent/src/routes/paths.ts
@@ -0,0 +1,30 @@
+export const rootPaths = {
+ homeRoot: '',
+ pagesRoot: 'pages',
+ applicationsRoot: 'applications',
+ ecommerceRoot: 'ecommerce',
+ authRoot: 'authentication',
+ notificationsRoot: 'notifications',
+ calendarRoot: 'calendar',
+ messageRoot: 'messages',
+ errorRoot: 'error',
+ educationRoot: 'education',
+ propertyRoot: 'property',
+ vendorsRoot: 'vendors',
+ termsOfServiceRoot: 'terms-of-service',
+};
+
+export default {
+ home: `/${rootPaths.homeRoot}`,
+ login: `/${rootPaths.authRoot}/login`,
+ signup: `/${rootPaths.authRoot}/sign-up`,
+ resetPassword: `/${rootPaths.authRoot}/reset-password`,
+ forgotPassword: `/${rootPaths.authRoot}/forgot-password`,
+ 404: `/${rootPaths.errorRoot}/404`,
+ education: `/${rootPaths.educationRoot}`,
+ educationLesson: `/${rootPaths.educationRoot}/lesson`,
+ property: `/${rootPaths.propertyRoot}`,
+ vendors: `/${rootPaths.vendorsRoot}`,
+ termsOfService: `/${rootPaths.termsOfServiceRoot}`,
+};
+
diff --git a/ditch-the-agent/src/routes/router.tsx b/ditch-the-agent/src/routes/router.tsx
new file mode 100644
index 0000000..1f838ee
--- /dev/null
+++ b/ditch-the-agent/src/routes/router.tsx
@@ -0,0 +1,203 @@
+import { ReactNode, Suspense, lazy, useContext } from 'react';
+import { Navigate, Outlet, RouteObject, RouterProvider, createBrowserRouter } from 'react-router-dom';
+
+import paths, { rootPaths } from './paths';
+
+import PageLoader from '../components/loading/PageLoader';
+import Splash from 'components/loading/Splash';
+import Education from 'pages/Education/Education';
+import Property from 'pages/Property/Property';
+import Vendors from 'pages/Vendors/Vendors';
+import EducationDetail from 'components/sections/dashboard/Home/Education/EducationDetail';
+import TermsOfService from 'pages/home/TermsOfService';
+import { AuthContext, AuthProvider } from 'contexts/AuthContext';
+
+const App = lazy(() => import('App'));
+const MainLayout = lazy(async () => {
+ return Promise.all([
+ import('layouts/main-layout'),
+ new Promise((resolve) => setTimeout(resolve, 1000)),
+ ]).then(([moduleExports]) => moduleExports);
+});
+const AuthLayout = lazy(async () => {
+ return Promise.all([
+ import('layouts/auth-layout'),
+ new Promise((resolve) => setTimeout(resolve, 1000)),
+ ]).then(([moduleExports]) => moduleExports);
+});
+
+const Error404 = lazy(async () => {
+ await new Promise((resolve) => setTimeout(resolve, 500));
+ return import('pages/errors/Error404');
+});
+
+const Sales = lazy(async () => {
+ return Promise.all([
+ import('pages/home/Sales'),
+ new Promise((resolve) => setTimeout(resolve, 500)),
+ ]).then(([moduleExports]) => moduleExports);
+});
+
+const Login = lazy(async () => import('pages/authentication/Login'));
+const SignUp = lazy(async () => import('pages/authentication/SignUp'));
+
+const ResetPassword = lazy(async () => import('pages/authentication/ResetPassword'));
+const ForgotPassword = lazy(async () => import('pages/authentication/ForgotPassword'));
+
+type ProtectedRouteProps = {
+ children?: ReactNode;
+}
+
+const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
+ const { authenticated, loading } = useContext(AuthContext);
+
+ if (!authenticated && !loading) {
+ return ;
+ }
+
+ return children;
+};
+
+const routes: RouteObject[] = [
+ {
+ element: (
+ }>
+
+
+ ),
+ children: [
+ {
+ path: rootPaths.homeRoot,
+ element: (
+
+
+ }>
+
+
+
+
+ ),
+ children: [
+ {
+ path: paths.home,
+ element: ,
+ },
+ ],
+ },
+ {
+ path: rootPaths.authRoot,
+ element: (
+
+ }>
+
+
+
+ ),
+ children: [
+ {
+ path: paths.login,
+ element: ,
+ },
+ {
+ path: paths.signup,
+ element: ,
+ },
+ {
+ path: paths.resetPassword,
+ element: ,
+ },
+ {
+ path: paths.forgotPassword,
+ element: ,
+ },
+ ],
+ },
+ // {
+ // path: rootPaths.termsOfServiceRoot,
+ // element: (
+ //
+ // }>
+ //
+ //
+ //
+ // ),
+ // children: [
+ // {
+ // path: paths.login,
+ // element: ,
+ // },
+ // ]
+ // },
+ {
+ path: rootPaths.propertyRoot,
+
+ element: (
+
+
+ }>
+
+
+
+
+ ),
+ children: [
+ {
+ path: paths.property,
+ element: ,
+ },
+ ],
+ },
+ {
+ path: rootPaths.educationRoot,
+
+ element: (
+
+
+ }>
+
+
+
+
+ ),
+ children: [
+ {
+ path: paths.education,
+ element: ,
+ },
+ {
+ path: paths.educationLesson,
+ element: ,
+ },
+ ],
+ },
+ {
+ path: rootPaths.vendorsRoot,
+
+ element: (
+
+
+ }>
+
+
+
+
+ ),
+ children: [
+ {
+ path: paths.vendors,
+ element: ,
+ },
+ ],
+ },
+ {
+ path: '*',
+ element: ,
+ },
+ ],
+ },
+];
+
+const router = createBrowserRouter(routes, { basename: '/elegent' });
+
+
+export default router;
diff --git a/ditch-the-agent/src/theme/colors.ts b/ditch-the-agent/src/theme/colors.ts
new file mode 100644
index 0000000..99eef46
--- /dev/null
+++ b/ditch-the-agent/src/theme/colors.ts
@@ -0,0 +1,109 @@
+export const orange = {
+ 50: '#FFC794',
+ 100: '#FFBB7F',
+ 200: '#FFBD69',
+ 300: '#FFA554',
+ 400: '#FF993E',
+ 500: '#FF8E29',
+ 600: '#CC7221',
+ 700: '#995519',
+ 800: '#663910',
+ 900: '#331C08',
+};
+
+export const caribbeanGreen = {
+ 100: '#D4F6EA',
+ 200: '#A9ECD5',
+ 300: '#7DE3BF',
+ 400: '#52D9AA',
+ 500: '#27D095',
+ 600: '#1FA677',
+ 700: '#177D59',
+ 800: '#10533C',
+ 900: '#082A1E',
+};
+
+export const downy = {
+ 100: '#E1F4F9',
+ 200: '#C2EAF2',
+ 300: '#A4DFEC',
+ 400: '#85D5E5',
+ 500: '#67CADF',
+ 600: '#52A2B2',
+ 700: '#3E7986',
+ 800: '#295159',
+ 900: '#15282D',
+};
+
+export const watermelon = {
+ 100: '#FDDCDF',
+ 200: '#FBB9BF',
+ 300: '#F9959F',
+ 400: '#F7727F',
+ 500: '#F54F5F',
+ 600: '#C43F4C',
+ 700: '#932F39',
+ 800: '#622026',
+ 900: '#311013',
+};
+
+export const black = {
+ 100: '#CDCFD3',
+ 200: '#9B9FA7',
+ 300: '#696F7C',
+ 400: '#373F50',
+ 500: '#050F24',
+ 600: '#040C1D',
+ 700: '#030916',
+ 800: '#02060E',
+ 900: '#010307',
+};
+
+export const smoke = {
+ 100: '#F5F5F5',
+ 200: '#CCCDCD',
+ 300: '#A9ACB2',
+ 400: '#8C9198',
+ 500: '#6F757E',
+ 600: '#595E65',
+ 700: '#43464C',
+ 800: '#2C2F32',
+ 900: '#161719',
+};
+
+export const white = {
+ 50: '#FFFFFF',
+ 100: '#F9F9F9',
+ 200: '#F3F3F3',
+ 300: '#EDEDED',
+ 400: '#E7E7E7',
+ 500: '#E1E1E1',
+ 600: '#B4B4B4',
+ 700: '#878787',
+ 800: '#5A5A5A',
+ 900: '#2D2D2D',
+};
+
+export const cream = {
+ 100: '#FFFDFB',
+ 200: '#FFFBF7',
+ 300: '#FFF8F2',
+ 400: '#FFF6EE',
+ 500: '#FFF4EA',
+ 600: '#CCC3BB',
+ 700: '#99928C',
+ 800: '#66625E',
+ 900: '#33312F',
+};
+
+export const dta_green = {
+ 100: '#2d4a4aff',
+ 200: '#2d4a4aff',
+ 300: '#2d4a4aff',
+ 400: '#2d4a4aff',
+ 500: '#2d4a4aff',
+ 600: '#2d4a4aff',
+ 700: '#2d4a4aff',
+ 800: '#2d4a4aff',
+ 900: '#2d4a4aff',
+}
diff --git a/ditch-the-agent/src/theme/components/AppBar.tsx b/ditch-the-agent/src/theme/components/AppBar.tsx
new file mode 100644
index 0000000..1078b11
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/AppBar.tsx
@@ -0,0 +1,14 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const AppBar: Components>['MuiAppBar'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({ theme }) => ({
+ backgroundColor: theme.palette.background.default,
+ boxShadow: theme.shadows[0],
+ }),
+ },
+};
+
+export default AppBar;
diff --git a/ditch-the-agent/src/theme/components/Avatar.tsx b/ditch-the-agent/src/theme/components/Avatar.tsx
new file mode 100644
index 0000000..344cce3
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Avatar.tsx
@@ -0,0 +1,14 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Avatar: Components>['MuiAvatar'] = {
+ defaultProps: {},
+ styleOverrides: {
+ img: () => ({
+ objectFit: 'cover',
+ overflow: 'auto',
+ }),
+ },
+};
+
+export default Avatar;
diff --git a/ditch-the-agent/src/theme/components/Badge.tsx b/ditch-the-agent/src/theme/components/Badge.tsx
new file mode 100644
index 0000000..b4b1a06
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Badge.tsx
@@ -0,0 +1,14 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Badge: Components>['MuiBadge'] = {
+ defaultProps: {},
+ styleOverrides: {
+ badge: ({ theme }) => ({
+ color: theme.palette.common.white,
+ padding: 0,
+ }),
+ },
+};
+
+export default Badge;
diff --git a/ditch-the-agent/src/theme/components/Button.tsx b/ditch-the-agent/src/theme/components/Button.tsx
new file mode 100644
index 0000000..6717afa
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Button.tsx
@@ -0,0 +1,84 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Button: Components>['MuiButton'] = {
+ defaultProps: {
+ size: 'medium',
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ fontSize: theme.typography.body1.fontSize,
+ fontWeight: theme.typography.body1.fontWeight,
+ paddingTop: theme.spacing(1.5),
+ paddingBottom: theme.spacing(1.5),
+ textTransform: 'none',
+ textAlign: 'center',
+ letterSpacing: 0,
+ }),
+ text: ({ theme }) => ({
+ color: theme.palette.primary.main,
+ padding: theme.spacing(1.5, 2),
+ borderRadius: 0,
+ '&:hover': {
+ backgroundColor: 'transparent',
+ },
+ }),
+ outlined: ({ theme }) => ({
+ border: 1,
+ borderStyle: 'solid',
+ borderRadius: theme.shape.borderRadius * 7.5,
+ }),
+ sizeSmall: ({ theme }) => ({
+ padding: theme.spacing(0.75, 3.375),
+ }),
+ sizeLarge: ({ theme }) => ({
+ padding: theme.spacing(1.5, 7.75),
+ }),
+ outlinedSizeLarge: ({ theme }) => ({
+ padding: theme.spacing(1.5, 7.75),
+ }),
+ contained: ({ theme }) => ({
+ backgroundColor: theme.palette.primary.main,
+ borderRadius: theme.shape.borderRadius * 7.5,
+ boxShadow: theme.shadows[0],
+ color: theme.palette.common.white,
+ '&:hover': {
+ boxShadow: theme.shadows[0],
+ },
+ }),
+ containedSizeLarge: ({ theme }) => ({
+ padding: theme.spacing(1.5, 7.75),
+ }),
+ icon: ({ theme }) => ({
+ paddingTop: theme.spacing(0.75),
+ paddingBottom: theme.spacing(0.75),
+ }),
+ fullWidth: ({ theme }) => ({
+ paddingTop: theme.spacing(1.5),
+ paddingBottom: theme.spacing(1.5),
+ }),
+ disabled: () => ({
+ cursor: 'not-allowed',
+ }),
+ containedSecondary: ({ theme }) => ({
+ backgroundColor: theme.palette.secondary.main,
+ }),
+ textSecondary: ({ theme }) => ({
+ color: theme.palette.secondary.main,
+ }),
+ containedInfo: ({ theme }) => ({
+ backgroundColor: theme.palette.info.main,
+ }),
+ textInfo: ({ theme }) => ({
+ color: theme.palette.info.main,
+ }),
+ containedError: ({ theme }) => ({
+ backgroundColor: theme.palette.error.main,
+ }),
+ textError: ({ theme }) => ({
+ color: theme.palette.error.main,
+ }),
+ },
+};
+
+export default Button;
diff --git a/ditch-the-agent/src/theme/components/Card.tsx b/ditch-the-agent/src/theme/components/Card.tsx
new file mode 100644
index 0000000..7fa6414
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Card.tsx
@@ -0,0 +1,20 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Card: Components>['MuiCard'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({ theme }) => ({
+ height: 'min-content',
+ padding: theme.spacing(2.5),
+ borderRadius: theme.shape.borderRadius * 5,
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ flexWrap: 'wrap',
+ gap: theme.spacing(2.5),
+ }),
+ },
+};
+
+export default Card;
diff --git a/ditch-the-agent/src/theme/components/Collapse.tsx b/ditch-the-agent/src/theme/components/Collapse.tsx
new file mode 100644
index 0000000..6665fbc
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Collapse.tsx
@@ -0,0 +1,14 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Collapse: Components>['MuiCollapse'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({ theme }) => ({
+ width: '100%',
+ borderRadius: theme.shape.borderRadius * 2,
+ }),
+ },
+};
+
+export default Collapse;
diff --git a/ditch-the-agent/src/theme/components/CssBaseline.tsx b/ditch-the-agent/src/theme/components/CssBaseline.tsx
new file mode 100644
index 0000000..c3e9fe5
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/CssBaseline.tsx
@@ -0,0 +1,22 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+import scrollbar from 'theme/styles/scrollbar';
+import echart from 'theme/styles/echart';
+import 'simplebar-react/dist/simplebar.min.css';
+import simplebar from 'theme/styles/simplebar';
+
+const CssBaseline: Components>['MuiCssBaseline'] = {
+ defaultProps: {},
+ styleOverrides: (theme) => ({
+ html: {
+ scrollBehavior: 'smooth',
+ },
+ body: {
+ ...scrollbar(theme),
+ },
+ ...echart(),
+ ...simplebar(theme),
+ }),
+};
+
+export default CssBaseline;
diff --git a/ditch-the-agent/src/theme/components/DataGrid/DataGrid.tsx b/ditch-the-agent/src/theme/components/DataGrid/DataGrid.tsx
new file mode 100644
index 0000000..3f816ef
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/DataGrid/DataGrid.tsx
@@ -0,0 +1,131 @@
+import { Theme } from '@mui/material';
+
+import type { DataGridComponents } from '@mui/x-data-grid/themeAugmentation';
+import pxToRem from 'theme/functions/px-to-rem';
+
+const DataGrid: DataGridComponents>['MuiDataGrid'] = {
+ defaultProps: {
+ disableRowSelectionOnClick: true,
+ disableColumnMenu: true,
+ pagination: true,
+ density: 'comfortable',
+ scrollbarSize: 1,
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ backgroundColor: theme.palette.background.paper,
+ border: 'none',
+ borderColor: theme.palette.divider,
+ '--DataGrid-rowBorderColor': theme.palette.background.paper,
+ '--DataGrid-containerBackground': theme.palette.background.paper,
+ borderBottomLeftRadius: theme.spacing(2.5),
+ borderBottomRightRadius: theme.spacing(2.5),
+ '& .MuiDataGrid-filler': {
+ flex: 0,
+ },
+ '& .MuiDataGrid-scrollbar--vertical': {
+ display: 'none',
+ },
+ }),
+ main: ({ theme }) => ({
+ marginLeft: theme.spacing(2.5),
+ marginRight: theme.spacing(2.5),
+ }),
+ 'container--top': ({ theme }) => ({
+ backgroundColor: theme.palette.background.paper,
+ '::after': {
+ content: 'none',
+ },
+ }),
+ columnHeaders: ({ theme }) => ({
+ borderBottom: 'none',
+ backgroundColor: theme.palette.background.paper,
+ }),
+ columnHeader: () => ({
+ '&:focus': {
+ outline: 'none',
+ },
+ '&:focus-within': {
+ outline: 'none',
+ },
+ }),
+ columnHeaderTitle: ({ theme }) => ({
+ fontSize: theme.typography.subtitle1.fontSize,
+ fontWeight: theme.typography.subtitle1.fontWeight,
+ }),
+ columnHeaderTitleContainer: () => ({
+ gap: 8,
+ }),
+ columnSeparator: () => ({
+ display: 'none',
+ }),
+ cell: ({ theme }) => ({
+ color: theme.palette.text.secondary,
+ fontSize: theme.typography.body1.fontSize,
+ fontWeight: theme.typography.body1.fontWeight,
+ fontFamily: theme.typography.body1.fontFamily,
+ border: 'none',
+ display: 'flex',
+ alignItems: 'center',
+ '&:focus': {
+ outline: 'none',
+ },
+ '&:focus-within': {
+ outline: 'none',
+ },
+ }),
+ row: ({ theme }) => ({
+ border: 'none',
+ width: '100%',
+ '&:hover': {
+ backgroundColor: theme.palette.background.default,
+ },
+ }),
+ virtualScroller: () => ({
+ overflowX: 'scroll !important' as 'scroll',
+ display: 'flex',
+ flexDirection: 'column',
+ height: pxToRem(432),
+ }),
+ virtualScrollerContent: () => ({
+ width: 'auto',
+ }),
+ virtualScrollerRenderZone: () => ({
+ width: 'auto',
+ position: 'static',
+ height: '100%',
+ }),
+ filler: () => ({
+ display: 'none',
+ height: '0 !important',
+ flex: 0,
+ flexGrow: 0,
+ }),
+ withBorderColor: ({ theme }) => ({
+ borderColor: theme.palette.divider,
+ }),
+ footerContainer: ({ theme }) => ({
+ borderBottomLeftRadius: theme.spacing(2.5),
+ borderBottomRightRadius: theme.spacing(2.5),
+ }),
+ cellEmpty: ({ theme }) => ({
+ width: theme.spacing(0),
+ maxWidth: theme.spacing(0),
+ }),
+ sortIcon: () => ({
+ color: 'initial',
+ width: 20,
+ }),
+ overlay: ({ theme }) => ({
+ backgroundColor: theme.palette.background.paper,
+ fontSize: theme.typography.subtitle1.fontSize,
+ fontWeight: theme.typography.subtitle1.fontWeight,
+ fontFamily: theme.typography.body1.fontFamily,
+ }),
+ overlayWrapperInner: () => ({
+ height: '100%',
+ }),
+ },
+};
+
+export default DataGrid;
diff --git a/ditch-the-agent/src/theme/components/FilledInput.tsx b/ditch-the-agent/src/theme/components/FilledInput.tsx
new file mode 100644
index 0000000..b48ed19
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/FilledInput.tsx
@@ -0,0 +1,70 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+import pxToRem from 'theme/functions/px-to-rem';
+
+const FilledInput: Components>['MuiFilledInput'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({ theme }) => ({
+ borderRadius: 999,
+ borderWidth: pxToRem(1),
+ borderStyle: 'solid',
+ borderColor: theme.palette.divider,
+ backgroundColor: theme.palette.action.focus,
+ '&:hover': {
+ backgroundColor: theme.palette.action.focus,
+ },
+ '&:focus': {
+ backgroundColor: theme.palette.action.focus,
+ },
+ '&.Mui-focused': {
+ backgroundColor: theme.palette.action.focus,
+ },
+ '&::before': {
+ border: 'none',
+ },
+ '&::after': {
+ border: 'none',
+ },
+ '&:hover:not(.Mui-disabled,.Mui-error):before': {
+ border: 'none',
+ },
+ }),
+ focused: ({ theme }) => ({
+ backgroundColor: theme.palette.action.focus,
+ }),
+ input: () => ({
+ paddingLeft: pxToRem(20),
+ paddingTop: pxToRem(12),
+ paddingBottom: pxToRem(12),
+ '&::placeholder': {
+ opacity: 1,
+ },
+ '&:-webkit-autofill': {
+ borderTopLeftRadius: 'inherit',
+ borderBottomLeftRadius: 'inherit',
+ borderTopRightRadius: 'initial',
+ borderBottomRightRadius: 'initial',
+ },
+ }),
+ error: ({ theme }) => ({
+ borderColor: theme.palette.error.main,
+ }),
+ adornedEnd: ({ theme }) => ({
+ color: theme.palette.common.black,
+ }),
+ inputAdornedEnd: ({ theme }) => ({
+ color: theme.palette.common.black,
+ }),
+ multiline: () => ({
+ alignItems: 'start',
+ minHeight: pxToRem(90),
+ paddingTop: 0,
+ paddingBottom: pxToRem(0),
+ paddingLeft: 0,
+ borderRadius: pxToRem(30),
+ }),
+ },
+};
+
+export default FilledInput;
diff --git a/ditch-the-agent/src/theme/components/FormControl.tsx b/ditch-the-agent/src/theme/components/FormControl.tsx
new file mode 100644
index 0000000..2d2996a
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/FormControl.tsx
@@ -0,0 +1,14 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+import pxToRem from 'theme/functions/px-to-rem';
+
+const FormControl: Components>['MuiFormControl'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: () => ({
+ gap: pxToRem(10),
+ }),
+ },
+};
+
+export default FormControl;
diff --git a/ditch-the-agent/src/theme/components/Grid2.tsx b/ditch-the-agent/src/theme/components/Grid2.tsx
new file mode 100644
index 0000000..7bd7349
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Grid2.tsx
@@ -0,0 +1,13 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Grid2: Components>['MuiGrid2'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: () => ({
+ marginRight: 0,
+ }),
+ },
+};
+
+export default Grid2;
diff --git a/ditch-the-agent/src/theme/components/IconButton.tsx b/ditch-the-agent/src/theme/components/IconButton.tsx
new file mode 100644
index 0000000..bfec503
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/IconButton.tsx
@@ -0,0 +1,23 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const IconButton: Components>['MuiIconButton'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({ theme }) => ({
+ maxWidth: 40,
+ maxHeight: 40,
+ padding: theme.spacing(1.5),
+ backgroundColor: theme.palette.action.focus,
+ '&:hover': {
+ backgroundColor: theme.palette.action.active,
+ },
+ }),
+ sizeSmall: () => ({
+ maxWidth: 20,
+ maxHeight: 20,
+ }),
+ },
+};
+
+export default IconButton;
diff --git a/ditch-the-agent/src/theme/components/Input.tsx b/ditch-the-agent/src/theme/components/Input.tsx
new file mode 100644
index 0000000..b8b3dd6
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Input.tsx
@@ -0,0 +1,15 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Input: Components>['MuiInput'] = {
+ defaultProps: {},
+ styleOverrides: {
+ input: ({ theme }) => ({
+ '&::placeholder': {
+ fontFamily: theme.typography.body1.fontFamily,
+ },
+ }),
+ },
+};
+
+export default Input;
diff --git a/ditch-the-agent/src/theme/components/InputAdornment.tsx b/ditch-the-agent/src/theme/components/InputAdornment.tsx
new file mode 100644
index 0000000..0655506
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/InputAdornment.tsx
@@ -0,0 +1,14 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const InputAdornment: Components>['MuiInputAdornment'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({ theme }) => ({
+ color: theme.palette.text.secondary,
+ margin: 0,
+ }),
+ },
+};
+
+export default InputAdornment;
diff --git a/ditch-the-agent/src/theme/components/InputBase.tsx b/ditch-the-agent/src/theme/components/InputBase.tsx
new file mode 100644
index 0000000..e3127db
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/InputBase.tsx
@@ -0,0 +1,31 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const InputBase: Components>['MuiInputBase'] = {
+ defaultProps: {
+ autoComplete: 'off',
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ color: theme.palette.text.primary,
+ fontSize: theme.typography.body1.fontSize,
+ fontWeight: theme.typography.body1.fontWeight,
+ maxWidth: 330,
+ }),
+ input: ({ theme }) => ({
+ '&::placeholder': {
+ opacity: 1,
+ fontFamily: theme.typography.body1.fontFamily,
+ color: theme.palette.text.secondary,
+ },
+ ':-webkit-autofill': {
+ borderTopLeftRadius: 'inherit',
+ borderBottomLeftRadius: 'inherit',
+ borderTopRightRadius: 'initial',
+ borderBottomRightRadius: 'initial',
+ },
+ }),
+ },
+};
+
+export default InputBase;
diff --git a/ditch-the-agent/src/theme/components/InputLabel.tsx b/ditch-the-agent/src/theme/components/InputLabel.tsx
new file mode 100644
index 0000000..6c1ac5e
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/InputLabel.tsx
@@ -0,0 +1,26 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const InputLabel: Components>['MuiInputLabel'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({ theme }) => ({
+ position: 'static',
+ transform: 'none',
+ transition: 'none',
+ fontSize: theme.typography.body1.fontSize,
+ fontWeight: theme.typography.body1.fontWeight,
+ '&.Mui-focused': {
+ color: theme.palette.text.secondary,
+ },
+ }),
+ focused: ({ theme }) => ({
+ color: theme.palette.text.secondary,
+ position: 'static',
+ transform: 'none',
+ transition: 'none',
+ }),
+ },
+};
+
+export default InputLabel;
diff --git a/ditch-the-agent/src/theme/components/Link.tsx b/ditch-the-agent/src/theme/components/Link.tsx
new file mode 100644
index 0000000..0c00ba0
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Link.tsx
@@ -0,0 +1,18 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+import { forwardRef } from 'react';
+import { Link as RouterLink, LinkProps as RouterLinkProps } from 'react-router-dom';
+
+const LinkBehavior = forwardRef & { href?: string }>(
+ (props, ref) => ,
+);
+
+const Link: Components>['MuiLink'] = {
+ defaultProps: {
+ underline: 'none',
+ component: LinkBehavior,
+ },
+ styleOverrides: {},
+};
+
+export default Link;
diff --git a/ditch-the-agent/src/theme/components/ListItem.tsx b/ditch-the-agent/src/theme/components/ListItem.tsx
new file mode 100644
index 0000000..4371360
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/ListItem.tsx
@@ -0,0 +1,17 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const ListItem: Components>['MuiListItem'] = {
+ defaultProps: {
+ disablePadding: true,
+ },
+ styleOverrides: {
+ root: ({}) => ({
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'start',
+ }),
+ },
+};
+
+export default ListItem;
diff --git a/ditch-the-agent/src/theme/components/ListItemButton.tsx b/ditch-the-agent/src/theme/components/ListItemButton.tsx
new file mode 100644
index 0000000..7eea8d5
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/ListItemButton.tsx
@@ -0,0 +1,19 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const ListItemButton: Components>['MuiListItemButton'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({ theme }) => ({
+ borderRadius: theme.shape.borderRadius * 2,
+ display: 'flex',
+ alignItems: 'center',
+ gap: theme.spacing(1.25),
+ paddingLeft: theme.spacing(1.25),
+ paddingRight: theme.spacing(1.25),
+ width: '100%',
+ }),
+ },
+};
+
+export default ListItemButton;
diff --git a/ditch-the-agent/src/theme/components/ListItemIcon.tsx b/ditch-the-agent/src/theme/components/ListItemIcon.tsx
new file mode 100644
index 0000000..13e73d6
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/ListItemIcon.tsx
@@ -0,0 +1,17 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const ListItemIcon: Components>['MuiListItemIcon'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({ theme }) => ({
+ width: theme.spacing(2.25),
+ height: theme.spacing(2.25),
+ color: 'inherit',
+ minWidth: 'auto',
+ alignItems: 'center',
+ }),
+ },
+};
+
+export default ListItemIcon;
diff --git a/ditch-the-agent/src/theme/components/ListItemText.tsx b/ditch-the-agent/src/theme/components/ListItemText.tsx
new file mode 100644
index 0000000..fb8a7a3
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/ListItemText.tsx
@@ -0,0 +1,15 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const ListItemText: Components>['MuiListItemText'] = {
+ defaultProps: {},
+ styleOverrides: {
+ primary: ({ theme }) => ({
+ fontSize: theme.typography.subtitle1.fontSize,
+ fontWeight: theme.typography.subtitle1.fontWeight,
+ fontFamily: theme.typography.fontFamily,
+ }),
+ },
+};
+
+export default ListItemText;
diff --git a/ditch-the-agent/src/theme/components/Menu.tsx b/ditch-the-agent/src/theme/components/Menu.tsx
new file mode 100644
index 0000000..349e998
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Menu.tsx
@@ -0,0 +1,14 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Menu: Components>['MuiMenu'] = {
+ defaultProps: {},
+ styleOverrides: {
+ paper: ({ theme }) => ({
+ minWidth: theme.spacing(22.625),
+ borderRadius: theme.shape.borderRadius * 2,
+ }),
+ },
+};
+
+export default Menu;
diff --git a/ditch-the-agent/src/theme/components/OutlinedInput.tsx b/ditch-the-agent/src/theme/components/OutlinedInput.tsx
new file mode 100644
index 0000000..c16982c
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/OutlinedInput.tsx
@@ -0,0 +1,50 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+import pxToRem from 'theme/functions/px-to-rem';
+
+const OutlinedInput: Components>['MuiOutlinedInput'] = {
+ defaultProps: {
+ autoComplete: 'off',
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ borderRadius: 999,
+ borderWidth: pxToRem(1),
+ borderStyle: 'solid',
+ borderColor: theme.palette.divider,
+ backgroundColor: theme.palette.background.paper,
+ '&.MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline': {
+ border: '1px solid black',
+ },
+ '&.MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline > legend': {
+ width: 0,
+ },
+ }),
+ input: ({ theme }) => ({
+ paddingLeft: pxToRem(20),
+ paddingTop: pxToRem(12),
+ paddingBottom: pxToRem(12),
+ '&::placeholder': {
+ opacity: 1,
+ color: theme.palette.text.secondary,
+ },
+ }),
+ notchedOutline: ({ theme }) => ({
+ borderColor: theme.palette.divider,
+ '&:hover': {
+ borderColor: theme.palette.primary.main,
+ },
+ '&:focus': {
+ borderColor: theme.palette.secondary.main,
+ },
+ }),
+ adornedEnd: ({ theme }) => ({
+ color: theme.palette.common.black,
+ }),
+ inputAdornedEnd: ({ theme }) => ({
+ color: theme.palette.common.black,
+ }),
+ },
+};
+
+export default OutlinedInput;
diff --git a/ditch-the-agent/src/theme/components/Pagination.tsx b/ditch-the-agent/src/theme/components/Pagination.tsx
new file mode 100644
index 0000000..76c2de1
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Pagination.tsx
@@ -0,0 +1,15 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Pagination: Components>['MuiPagination'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({}) => ({}),
+ ul: ({ theme }) => ({
+ display: 'flex',
+ gap: theme.spacing(1.125),
+ }),
+ },
+};
+
+export default Pagination;
diff --git a/ditch-the-agent/src/theme/components/PaginationItem.tsx b/ditch-the-agent/src/theme/components/PaginationItem.tsx
new file mode 100644
index 0000000..dd04567
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/PaginationItem.tsx
@@ -0,0 +1,23 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const PaginationItem: Components>['MuiPaginationItem'] = {
+ defaultProps: {
+ selected: true,
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ color: theme.palette.primary.main,
+ fontSize: theme.typography.body1.fontSize,
+ fontWeight: theme.typography.subtitle1.fontWeight,
+ }),
+ previousNext: () => ({
+ borderRadius: 0,
+ }),
+ page: () => ({
+ borderRadius: 999,
+ }),
+ },
+};
+
+export default PaginationItem;
diff --git a/ditch-the-agent/src/theme/components/Paper.tsx b/ditch-the-agent/src/theme/components/Paper.tsx
new file mode 100644
index 0000000..9f66356
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Paper.tsx
@@ -0,0 +1,13 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Paper: Components>['MuiPaper'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({ theme }) => ({
+ backgroundColor: theme.palette.background.paper,
+ }),
+ },
+};
+
+export default Paper;
diff --git a/ditch-the-agent/src/theme/components/Stack.tsx b/ditch-the-agent/src/theme/components/Stack.tsx
new file mode 100644
index 0000000..77c8f71
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Stack.tsx
@@ -0,0 +1,9 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Stack: Components>['MuiStack'] = {
+ defaultProps: { useFlexGap: true },
+ styleOverrides: {},
+};
+
+export default Stack;
diff --git a/ditch-the-agent/src/theme/components/TablePagination.tsx b/ditch-the-agent/src/theme/components/TablePagination.tsx
new file mode 100644
index 0000000..eb510d7
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/TablePagination.tsx
@@ -0,0 +1,47 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const TablePagination: Components>['MuiTablePagination'] = {
+ defaultProps: {},
+ styleOverrides: {
+ root: ({ theme }) => ({
+ width: '100%',
+ ':last-child': {
+ borderRadius: theme.shape.borderRadius * 5,
+ },
+ borderRadius: theme.shape.borderRadius * 5,
+ }),
+ toolbar: ({ theme }) => ({
+ display: 'flex',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ flexDirection: 'row',
+ padding: theme.spacing(2.5, 3.75),
+ paddingRight: `${theme.spacing(3.75)} !important`,
+ [theme.breakpoints.down('sm')]: {
+ flexDirection: 'column',
+ gap: 15,
+ },
+ }),
+ spacer: {
+ flex: 'none',
+ },
+ select: {
+ display: 'none !important',
+ },
+ selectLabel: {
+ display: 'none',
+ },
+ input: {
+ display: 'none',
+ },
+ displayedRows: () => ({
+ display: 'none',
+ }),
+ actions: {
+ marginLeft: 'auto',
+ },
+ },
+};
+
+export default TablePagination;
diff --git a/ditch-the-agent/src/theme/components/TextField.tsx b/ditch-the-agent/src/theme/components/TextField.tsx
new file mode 100644
index 0000000..1f46b56
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/TextField.tsx
@@ -0,0 +1,16 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+import pxToRem from 'theme/functions/px-to-rem';
+
+const TextField: Components>['MuiTextField'] = {
+ defaultProps: {
+ variant: 'filled',
+ },
+ styleOverrides: {
+ root: {
+ gap: pxToRem(10),
+ },
+ },
+};
+
+export default TextField;
diff --git a/ditch-the-agent/src/theme/components/Toolbar.tsx b/ditch-the-agent/src/theme/components/Toolbar.tsx
new file mode 100644
index 0000000..20445de
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Toolbar.tsx
@@ -0,0 +1,16 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Toolbar: Components>['MuiToolbar'] = {
+ defaultProps: {
+ disableGutters: true,
+ },
+ styleOverrides: {
+ root: () => ({
+ display: 'flex',
+ justifyContent: 'space-between',
+ }),
+ },
+};
+
+export default Toolbar;
diff --git a/ditch-the-agent/src/theme/components/Tooltip.tsx b/ditch-the-agent/src/theme/components/Tooltip.tsx
new file mode 100644
index 0000000..ddeda75
--- /dev/null
+++ b/ditch-the-agent/src/theme/components/Tooltip.tsx
@@ -0,0 +1,16 @@
+import { Theme } from '@mui/material';
+import { Components } from '@mui/material/styles/components';
+
+const Tooltip: Components>['MuiTooltip'] = {
+ defaultProps: {},
+ styleOverrides: {
+ arrow: ({ theme }) => ({
+ color: theme.palette.common.black,
+ }),
+ tooltip: ({ theme }) => ({
+ backgroundColor: theme.palette.common.black,
+ }),
+ },
+};
+
+export default Tooltip;
diff --git a/ditch-the-agent/src/theme/functions/px-to-rem.ts b/ditch-the-agent/src/theme/functions/px-to-rem.ts
new file mode 100644
index 0000000..37121ce
--- /dev/null
+++ b/ditch-the-agent/src/theme/functions/px-to-rem.ts
@@ -0,0 +1,5 @@
+function pxToRem(number: number, baseNumber: number = 16) {
+ return `${number / baseNumber}rem`;
+}
+
+export default pxToRem;
diff --git a/ditch-the-agent/src/theme/palette.ts b/ditch-the-agent/src/theme/palette.ts
new file mode 100644
index 0000000..bde1845
--- /dev/null
+++ b/ditch-the-agent/src/theme/palette.ts
@@ -0,0 +1,41 @@
+import { PaletteOptions } from '@mui/material';
+import { caribbeanGreen, orange, downy, watermelon, black, smoke, white, cream, dta_green } from './colors';
+import { green, yellow } from '@mui/material/colors';
+
+const palette: PaletteOptions = {
+ primary: {
+ main: dta_green[100],//orange[500],
+ },
+ secondary: {
+ main: caribbeanGreen[500],
+ },
+ info: {
+ main: downy[500],
+ },
+ success: {
+ main: green[500],
+ },
+ error: {
+ main: watermelon[500],
+ },
+ text: {
+ primary: black[500],
+ secondary: smoke[500],
+ disabled: smoke[200],
+ },
+ action: {
+ focus: smoke[100],
+ disabled: smoke[400],
+ active: white[300],
+ },
+ background: {
+ default: dta_green[100],
+ paper: white[50],
+ },
+ divider: white[500],
+ warning: {
+ main: yellow[800],
+ },
+};
+
+export default palette;
diff --git a/ditch-the-agent/src/theme/shadows.ts b/ditch-the-agent/src/theme/shadows.ts
new file mode 100644
index 0000000..b200d07
--- /dev/null
+++ b/ditch-the-agent/src/theme/shadows.ts
@@ -0,0 +1,10 @@
+const shadows = [
+ `none`,
+ `0px 0px 5px 1px rgba(0, 0, 0, 0.2)`,
+ `0px 4px 10px 2px rgba(0, 0, 0, 0.2)`,
+ `0px 4px 4px 0px rgba(0, 0, 0, 0.25)`,
+ `0px 0px 4px 0px rgba(255, 142, 41, 0.1)`,
+ `0px 0px 5px 0px rgba(0, 0, 0, 0.15)`,
+];
+
+export default shadows;
diff --git a/ditch-the-agent/src/theme/styles/echart.ts b/ditch-the-agent/src/theme/styles/echart.ts
new file mode 100644
index 0000000..d826cd0
--- /dev/null
+++ b/ditch-the-agent/src/theme/styles/echart.ts
@@ -0,0 +1,13 @@
+const echart = () => ({
+ '.echarts-for-react': {
+ overflow: 'hidden',
+ '&:not(&.echart-map)': {
+ '> div': {
+ '&:first-of-type': {
+ height: '100% !important',
+ },
+ },
+ },
+ },
+});
+export default echart;
diff --git a/ditch-the-agent/src/theme/styles/scrollbar.ts b/ditch-the-agent/src/theme/styles/scrollbar.ts
new file mode 100644
index 0000000..4e27e42
--- /dev/null
+++ b/ditch-the-agent/src/theme/styles/scrollbar.ts
@@ -0,0 +1,31 @@
+import { Theme } from '@mui/material';
+
+const scrollbar = (theme: Theme) => ({
+ '@supports (-moz-appearance:none)': {
+ scrollbarColor: `${theme.palette.grey[300]} transparent`,
+ },
+ '*::-webkit-scrollbar': {
+ position: 'absolute',
+ visibility: 'hidden',
+ WebkitAppearance: 'none',
+ width: 5,
+ height: 5,
+ zIndex: 5,
+ backgroundColor: 'transparent',
+ },
+ '*::-webkit-scrollbar-track': {
+ margin: 9,
+ },
+ '*::-webkit-scrollbar-thumb': {
+ visibility: 'hidden',
+ borderRadius: 3,
+ backgroundColor: theme.palette.grey[300],
+ },
+ '&:hover, &:focus': {
+ '*::-webkit-scrollbar, *::-webkit-scrollbar-thumb': {
+ visibility: 'visible',
+ },
+ },
+});
+
+export default scrollbar;
diff --git a/ditch-the-agent/src/theme/styles/simplebar.ts b/ditch-the-agent/src/theme/styles/simplebar.ts
new file mode 100644
index 0000000..9c5371b
--- /dev/null
+++ b/ditch-the-agent/src/theme/styles/simplebar.ts
@@ -0,0 +1,34 @@
+import { Theme } from '@mui/material';
+
+const simplebar = (theme: Theme) => ({
+ '& .simplebar-track': {
+ '&.simplebar-vertical': {
+ '& .simplebar-scrollbar': {
+ '&:before': {
+ cursor: 'grab',
+ border: 1,
+ borderStyle: 'solid',
+ borderColor: theme.palette.common.white,
+ maxHeight: '100vh',
+ background: `${theme.palette.grey[300]}`,
+ '&:hover': {
+ backgroundColor: theme.palette.grey[800],
+ },
+ },
+
+ '&.simplebar-visible': {
+ '&:before': {
+ opacity: 1,
+ padding: 0,
+ },
+ },
+ },
+ },
+ },
+ '& .simplebar-wrapper': {
+ '& .simplebar-content': {
+ overflow: 'hidden',
+ },
+ },
+});
+export default simplebar;
diff --git a/ditch-the-agent/src/theme/theme.ts b/ditch-the-agent/src/theme/theme.ts
new file mode 100644
index 0000000..baeabe1
--- /dev/null
+++ b/ditch-the-agent/src/theme/theme.ts
@@ -0,0 +1,82 @@
+import { createTheme } from '@mui/material';
+
+import TablePagination from './components/TablePagination';
+import PaginationItem from './components/PaginationItem';
+import InputAdornment from './components/InputAdornment';
+import ListItemButton from './components/ListItemButton';
+import OutlinedInput from './components/OutlinedInput';
+import DataGrid from './components/DataGrid/DataGrid';
+import ListItemIcon from './components/ListItemIcon';
+import ListItemText from './components/ListItemText';
+import CssBaseline from './components/CssBaseline';
+import FilledInput from './components/FilledInput';
+import IconButton from './components/IconButton';
+import InputLabel from './components/InputLabel';
+import Pagination from './components/Pagination';
+import TextField from './components/TextField';
+import InputBase from './components/InputBase';
+import Toolbar from './components/Toolbar';
+import AppBar from './components/AppBar';
+import Avatar from './components/Avatar';
+import Button from './components/Button';
+import Badge from './components/Badge';
+import Grid2 from './components/Grid2';
+import Input from './components/Input';
+import Paper from './components/Paper';
+import Stack from './components/Stack';
+import Card from './components/Card';
+import Link from './components/Link';
+import Menu from './components/Menu';
+
+import typography from './typography';
+import palette from './palette';
+import shadows from './shadows';
+import Collapse from './components/Collapse';
+import ListItem from './components/ListItem';
+import Tooltip from './components/Tooltip';
+import FormControl from './components/FormControl';
+
+export const theme = createTheme({
+ typography: typography,
+ palette: palette,
+ components: {
+ MuiTablePagination: TablePagination,
+ MuiInputAdornment: InputAdornment,
+ MuiListItemButton: ListItemButton,
+ MuiPaginationItem: PaginationItem,
+ MuiOutlinedInput: OutlinedInput,
+ MuiListItemIcon: ListItemIcon,
+ MuiListItemText: ListItemText,
+ MuiCssBaseline: CssBaseline,
+ MuiFilledInput: FilledInput,
+ MuiFormControl: FormControl,
+ MuiIconButton: IconButton,
+ MuiPagination: Pagination,
+ MuiInputLabel: InputLabel,
+ MuiInputBase: InputBase,
+ MuiTextField: TextField,
+ MuiCollapse: Collapse,
+ MuiDataGrid: DataGrid,
+ MuiListItem: ListItem,
+ MuiToolbar: Toolbar,
+ MuiTooltip: Tooltip,
+ MuiAppBar: AppBar,
+ MuiAvatar: Avatar,
+ MuiButton: Button,
+ MuiBadge: Badge,
+ MuiGrid2: Grid2,
+ MuiInput: Input,
+ MuiPaper: Paper,
+ MuiStack: Stack,
+ MuiCard: Card,
+ MuiLink: Link,
+ MuiMenu: Menu,
+ },
+ zIndex: {
+ appBar: 1100,
+ },
+});
+
+shadows.forEach((shadow, index) => {
+ theme.shadows[index] = shadow;
+});
diff --git a/ditch-the-agent/src/theme/typography.ts b/ditch-the-agent/src/theme/typography.ts
new file mode 100644
index 0000000..4e17d11
--- /dev/null
+++ b/ditch-the-agent/src/theme/typography.ts
@@ -0,0 +1,64 @@
+import { TypographyOptions } from '@mui/material/styles/createTypography';
+import pxToRem from './functions/px-to-rem';
+
+const typography: TypographyOptions = {
+ fontFamily: ['IBM Plex Sans', 'Poppins', 'sans-serif'].join(','),
+ h1: {
+ fontSize: pxToRem(40),
+ fontWeight: 700,
+ fontFamily: 'IBM Plex Sans',
+ },
+ h2: {
+ fontSize: pxToRem(28),
+ fontWeight: 700,
+ fontFamily: 'IBM Plex Sans',
+ },
+ h3: {
+ fontSize: pxToRem(25),
+ fontWeight: 700,
+ fontFamily: 'IBM Plex Sans',
+ },
+ h4: {
+ fontSize: pxToRem(22),
+ fontWeight: 700,
+ fontFamily: 'IBM Plex Sans',
+ },
+ h5: {
+ fontSize: pxToRem(20),
+ fontWeight: 500,
+ fontFamily: 'IBM Plex Sans',
+ },
+ h6: {
+ fontSize: pxToRem(18),
+ fontWeight: 500,
+ fontFamily: 'IBM Plex Sans',
+ },
+ subtitle1: {
+ fontSize: pxToRem(16),
+ fontWeight: 500,
+ fontFamily: 'IBM Plex Sans',
+ },
+ subtitle2: {
+ fontSize: pxToRem(16),
+ fontWeight: 400,
+ fontFamily: 'IBM Plex Sans',
+ },
+ body1: {
+ fontSize: pxToRem(14),
+ fontWeight: 400,
+ fontFamily: 'Poppins',
+ },
+ body2: {
+ fontSize: pxToRem(12),
+ fontWeight: 400,
+ fontFamily: 'Poppins',
+ },
+ caption: {
+ fontFamily: 'Poppins',
+ },
+ button: {
+ fontFamily: 'Poppins',
+ },
+};
+
+export default typography;
diff --git a/ditch-the-agent/src/vite-env.d.ts b/ditch-the-agent/src/vite-env.d.ts
new file mode 100644
index 0000000..7d0ff9e
--- /dev/null
+++ b/ditch-the-agent/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/ditch-the-agent/tsconfig.json b/ditch-the-agent/tsconfig.json
new file mode 100644
index 0000000..e7ae797
--- /dev/null
+++ b/ditch-the-agent/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "useUnknownInCatchVariables": false,
+ "paths": {
+ "*": ["./src/*"]
+ }
+ },
+ "include": ["src"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/ditch-the-agent/tsconfig.node.json b/ditch-the-agent/tsconfig.node.json
new file mode 100644
index 0000000..b850582
--- /dev/null
+++ b/ditch-the-agent/tsconfig.node.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true,
+ "strict": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/ditch-the-agent/vite.config.ts b/ditch-the-agent/vite.config.ts
new file mode 100644
index 0000000..b633c10
--- /dev/null
+++ b/ditch-the-agent/vite.config.ts
@@ -0,0 +1,19 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+import tsconfigPaths from 'vite-tsconfig-paths';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ optimizeDeps: {
+ include: ['@emotion/react', '@emotion/styled', '@mui/material/Tooltip'],
+ },
+ plugins: [tsconfigPaths(), react()],
+ preview: {
+ port: 5000,
+ },
+ server: {
+ host: '0.0.0.0',
+ port: 3000,
+ },
+ base: '/elegent',
+});