From 68166b2f4c09621282e3fefbc97a37036d3e3062 Mon Sep 17 00:00:00 2001 From: joanne-ch Date: Wed, 15 Feb 2023 22:27:03 +0800 Subject: [PATCH 1/3] added graphs --- apps/cms/package.json | 5 + apps/cms/src/admin/components/Budget.tsx | 75 +++++++ apps/cms/src/admin/components/LatestOrder.tsx | 168 +++++++++++++++ apps/cms/src/admin/components/LineChart.tsx | 45 ++++ .../cms/src/admin/components/SeverityPill.tsx | 57 +++++ .../src/admin/components/TotalCustomers.tsx | 71 +++++++ apps/cms/src/admin/components/TotalProfit.tsx | 46 ++++ apps/cms/src/admin/components/UseChart.tsx | 198 ++++++++++++++++++ apps/cms/src/admin/views/MerchSales.tsx | 111 +++++++++- 9 files changed, 775 insertions(+), 1 deletion(-) create mode 100644 apps/cms/src/admin/components/Budget.tsx create mode 100644 apps/cms/src/admin/components/LatestOrder.tsx create mode 100644 apps/cms/src/admin/components/LineChart.tsx create mode 100644 apps/cms/src/admin/components/SeverityPill.tsx create mode 100644 apps/cms/src/admin/components/TotalCustomers.tsx create mode 100644 apps/cms/src/admin/components/TotalProfit.tsx create mode 100644 apps/cms/src/admin/components/UseChart.tsx diff --git a/apps/cms/package.json b/apps/cms/package.json index 73f72358..c32bf930 100644 --- a/apps/cms/package.json +++ b/apps/cms/package.json @@ -15,10 +15,15 @@ "generate:graphQLSchema": "PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:graphQLSchema" }, "dependencies": { + "@mui/icons-material": "^5.11.9", + "@mui/material": "^5.11.9", + "apexcharts": "^3.37.0", "dotenv": "^8.2.0", "express": "^4.17.1", "payload": "^1.3.4", "react": "^18.0.0", + "react-apexcharts": "^1.4.0", + "react-perfect-scrollbar": "^1.5.8", "tsconfig": "*" }, "devDependencies": { diff --git a/apps/cms/src/admin/components/Budget.tsx b/apps/cms/src/admin/components/Budget.tsx new file mode 100644 index 00000000..52c92f47 --- /dev/null +++ b/apps/cms/src/admin/components/Budget.tsx @@ -0,0 +1,75 @@ +import React from "react"; +import { Avatar, Box, Card, CardContent, Grid, Typography } from '@mui/material'; +import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'; +import MoneyIcon from '@mui/icons-material/Money'; + +const Budget = (props) => { + return ( + + + + + + BUDGET + + + $24k + + + + + + + + + + + + 12% + + + Since last month + + + + + + ); +} + +export default Budget; \ No newline at end of file diff --git a/apps/cms/src/admin/components/LatestOrder.tsx b/apps/cms/src/admin/components/LatestOrder.tsx new file mode 100644 index 00000000..6a97149f --- /dev/null +++ b/apps/cms/src/admin/components/LatestOrder.tsx @@ -0,0 +1,168 @@ +import React from "react"; +import { format } from 'date-fns'; +import { v4 as uuid } from 'uuid'; +import PerfectScrollbar from 'react-perfect-scrollbar'; +import { + Box, + Button, + Card, + CardHeader, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + TableSortLabel, + Tooltip +} from '@mui/material'; +import ArrowRightIcon from '@mui/icons-material/ArrowRight'; +import { SeverityPill } from './SeverityPill'; + +const orders = [ + { + id: uuid(), + ref: 'Merch 1', + amount: 30.5, + customer: { + name: 'Ekaterina Tankova' + }, + createdAt: 1555016400000, + status: 'pending' + }, + { + id: uuid(), + ref: 'Merch 2', + amount: 25.1, + customer: { + name: 'Cao Yu' + }, + createdAt: 1555016400000, + status: 'delivered' + }, + { + id: uuid(), + ref: 'Merch 3', + amount: 10.99, + customer: { + name: 'Alexa Richardson' + }, + createdAt: 1554930000000, + status: 'refunded' + }, + { + id: uuid(), + ref: 'Merch 4', + amount: 96.43, + customer: { + name: 'Anje Keizer' + }, + createdAt: 1554757200000, + status: 'pending' + }, + { + id: uuid(), + ref: 'Merch 5', + amount: 32.54, + customer: { + name: 'Clarke Gillebert' + }, + createdAt: 1554670800000, + status: 'delivered' + }, + { + id: uuid(), + ref: 'Merch 5', + amount: 16.76, + customer: { + name: 'Adam Denisov' + }, + createdAt: 1554670800000, + status: 'delivered' + } + ]; + + +const LatestOrder = (props) => { + return ( + + + + + + + + + Merch Ordered + + + Customer + + + + + Date + + + + + Status + + + + + {orders.map((order) => ( + + + {order.ref} + + + {order.customer.name} + + + {format(order.createdAt, 'dd/MM/yyyy')} + + + + {order.status} + + + + ))} + +
+
+
+ + + +
+ ); +} + +export default LatestOrder; \ No newline at end of file diff --git a/apps/cms/src/admin/components/LineChart.tsx b/apps/cms/src/admin/components/LineChart.tsx new file mode 100644 index 00000000..cae80a8a --- /dev/null +++ b/apps/cms/src/admin/components/LineChart.tsx @@ -0,0 +1,45 @@ +import React from "react"; +import useChart from './UseChart'; + +import dynamic from 'next/dynamic' +const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }); + + +import {Card, CardHeader, Box} from '@mui/material'; + +const LineChart = ({title, subheader, chartLabels, chartData, ...other}) => { + + const chartOptions = useChart({ + plotOptions: { bar: { columnWidth: '16%' } }, + fill: { type: chartData.map((i) => i.fill) }, + labels: chartLabels, + xaxis: { type: 'datetime' }, + tooltip: { + shared: true, + intersect: false, + y: { + formatter: (y) => { + if (typeof y !== 'undefined') { + return `${y.toFixed(0)} sales`; + } + return y; + }, + }, + }, + }); + + return ( + + + + + + + + ); +} + +export default LineChart; \ No newline at end of file diff --git a/apps/cms/src/admin/components/SeverityPill.tsx b/apps/cms/src/admin/components/SeverityPill.tsx new file mode 100644 index 00000000..e3049540 --- /dev/null +++ b/apps/cms/src/admin/components/SeverityPill.tsx @@ -0,0 +1,57 @@ +import React from "react"; +import PropTypes from 'prop-types'; +import { styled } from '@mui/material/styles'; + +const SeverityPillRoot = styled('span')(({ theme }) => { +// const backgroundColor = theme.palette[ownerState.color].main; +// const color = theme.palette[ownerState.color].contrastText; + + return { + alignItems: 'center', + // backgroundColor, + borderRadius: 12, + // color, + cursor: 'default', + display: 'inline-flex', + flexGrow: 0, + flexShrink: 0, + fontFamily: theme.typography.fontFamily, + fontSize: theme.typography.pxToRem(12), + lineHeight: 2, + fontWeight: 600, + justifyContent: 'center', + letterSpacing: 0.5, + minWidth: 20, + paddingLeft: theme.spacing(1), + paddingRight: theme.spacing(1), + textTransform: 'uppercase', + whiteSpace: 'nowrap' + }; +}); + +export const SeverityPill = (props) => { + const { color = 'primary', children, ...other } = props; + + const ownerState = { color }; + + return ( + + {children} + + ); +}; + +SeverityPill.propTypes = { + children: PropTypes.node, + color: PropTypes.oneOf([ + 'primary', + 'secondary', + 'error', + 'info', + 'warning', + 'success' + ]) +}; diff --git a/apps/cms/src/admin/components/TotalCustomers.tsx b/apps/cms/src/admin/components/TotalCustomers.tsx new file mode 100644 index 00000000..8d7c14e6 --- /dev/null +++ b/apps/cms/src/admin/components/TotalCustomers.tsx @@ -0,0 +1,71 @@ +import React from "react"; + +import { Avatar, Box, Card, CardContent, Grid, Typography } from '@mui/material'; +import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward'; +import PeopleIcon from '@mui/icons-material/PeopleOutlined'; + +const TotalCustomers = (props) => { + return ( + + + + + + TOTAL CUSTOMERS + + + 1,6k + + + + + + + + + + + + 16% + + + Since last month + + + + + ); +} + +export default TotalCustomers; \ No newline at end of file diff --git a/apps/cms/src/admin/components/TotalProfit.tsx b/apps/cms/src/admin/components/TotalProfit.tsx new file mode 100644 index 00000000..f9eccc22 --- /dev/null +++ b/apps/cms/src/admin/components/TotalProfit.tsx @@ -0,0 +1,46 @@ +import React from "react"; +import { Avatar, Card, CardContent, Grid, Typography } from '@mui/material'; +import AttachMoneyIcon from '@mui/icons-material/AttachMoney'; + +const TotalProfit = (props) => { + return ( + + + + + + TOTAL PROFIT + + + $23k + + + + + + + + + + + ); +} + +export default TotalProfit; \ No newline at end of file diff --git a/apps/cms/src/admin/components/UseChart.tsx b/apps/cms/src/admin/components/UseChart.tsx new file mode 100644 index 00000000..de540669 --- /dev/null +++ b/apps/cms/src/admin/components/UseChart.tsx @@ -0,0 +1,198 @@ +import merge from 'lodash/merge'; +import { useTheme, alpha } from '@mui/material/styles'; + + +export default function useChart(options) { + const theme = useTheme(); + + const LABEL_TOTAL = { + show: true, + label: 'Total', + color: theme.palette.text.secondary, + fontSize: theme.typography.subtitle2.fontSize, + fontWeight: theme.typography.subtitle2.fontWeight, + lineHeight: theme.typography.subtitle2.lineHeight, + }; + + const LABEL_VALUE = { + offsetY: 8, + color: theme.palette.text.primary, + fontSize: theme.typography.h3.fontSize, + fontWeight: theme.typography.h3.fontWeight, + lineHeight: theme.typography.h3.lineHeight, + }; + + const baseOptions = { + // Colors + colors: [ + theme.palette.primary.main, + theme.palette.warning.main, + theme.palette.info.main, + theme.palette.error.main, + theme.palette.success.main, + theme.palette.warning.dark, + theme.palette.success.dark, + theme.palette.info.dark, + theme.palette.info.dark, + ], + + // Chart + chart: { + toolbar: { show: false }, + zoom: { enabled: false }, + // animations: { enabled: false }, + foreColor: theme.palette.text.disabled, + fontFamily: theme.typography.fontFamily, + }, + + // States + states: { + hover: { + filter: { + type: 'lighten', + value: 0.04, + }, + }, + active: { + filter: { + type: 'darken', + value: 0.88, + }, + }, + }, + + // Fill + fill: { + opacity: 1, + gradient: { + type: 'vertical', + shadeIntensity: 0, + opacityFrom: 0.4, + opacityTo: 0, + stops: [0, 100], + }, + }, + + // Datalabels + dataLabels: { enabled: false }, + + // Stroke + stroke: { + width: 3, + curve: 'smooth', + lineCap: 'round', + }, + + // Grid + grid: { + strokeDashArray: 3, + borderColor: theme.palette.divider, + }, + + // Xaxis + xaxis: { + axisBorder: { show: false }, + axisTicks: { show: false }, + }, + + // Markers + markers: { + size: 0, + strokeColors: theme.palette.background.paper, + }, + + // Tooltip + tooltip: { + x: { + show: false, + }, + }, + + // Legend + legend: { + show: true, + fontSize: String(13), + position: 'top', + horizontalAlign: 'right', + markers: { + radius: 12, + }, + fontWeight: 500, + itemMargin: { horizontal: 12 }, + labels: { + colors: theme.palette.text.primary, + }, + }, + + // plotOptions + plotOptions: { + // Bar + bar: { + borderRadius: 4, + columnWidth: '28%', + }, + + // Pie + Donut + pie: { + donut: { + labels: { + show: true, + value: LABEL_VALUE, + total: LABEL_TOTAL, + }, + }, + }, + + // Radialbar + radialBar: { + track: { + strokeWidth: '100%', + background: alpha(theme.palette.grey[500], 0.16), + }, + dataLabels: { + value: LABEL_VALUE, + total: LABEL_TOTAL, + }, + }, + + // Radar + radar: { + polygons: { + fill: { colors: ['transparent'] }, + strokeColors: theme.palette.divider, + connectorColors: theme.palette.divider, + }, + }, + + // polarArea + polarArea: { + rings: { + strokeColor: theme.palette.divider, + }, + spokes: { + connectorColors: theme.palette.divider, + }, + }, + }, + + // Responsive + responsive: [ + { + // sm + breakpoint: theme.breakpoints.values.sm, + options: { + plotOptions: { bar: { columnWidth: '40%' } }, + }, + }, + { + // md + breakpoint: theme.breakpoints.values.md, + options: { + plotOptions: { bar: { columnWidth: '32%' } }, + }, + }, + ], + }; + + return merge(baseOptions, options); +} diff --git a/apps/cms/src/admin/views/MerchSales.tsx b/apps/cms/src/admin/views/MerchSales.tsx index 35bfbc15..b71211f9 100644 --- a/apps/cms/src/admin/views/MerchSales.tsx +++ b/apps/cms/src/admin/views/MerchSales.tsx @@ -2,6 +2,12 @@ import React from "react"; import { Button } from 'payload/components/elements'; import { AdminView } from 'payload/config'; import ViewTemplate from "./ViewTemplate"; +import LatestOrder from "../components/LatestOrder"; +import TotalCustomers from "../components/TotalCustomers"; +import TotalProfit from "../components/TotalProfit"; +import Budget from "../components/Budget"; +import LineChart from "../components/LineChart"; +import {Box, Container, Grid} from '@mui/material'; const MerchSales: AdminView = ({ user, canAccessAdmin }) => { return ( @@ -12,7 +18,110 @@ const MerchSales: AdminView = ({ user, canAccessAdmin }) => { keywords="" title="Merchandise Sales" > -

Here is a custom route that was added in the Payload config. It uses the Default Template, so the sidebar is rendered.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +