QQQ-41: added app sections, wired all dashboards, implemented widgets that could be, upped version

This commit is contained in:
Tim Chamberlain
2022-09-16 10:27:50 -05:00
parent b3f32572dc
commit f1300d2db9
49 changed files with 33588 additions and 32045 deletions

View File

@ -22,31 +22,124 @@
import Card from "@mui/material/Card";
import Divider from "@mui/material/Divider";
import Icon from "@mui/material/Icon";
import {useMemo, ReactNode} from "react";
import parse from "html-react-parser";
import {useMemo} from "react";
import {Bar} from "react-chartjs-2";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
import configs from "qqq/pages/dashboards/Widgets/Configs/BarChartConfig";
import {GenericChartDataSingleDataset} from "qqq/pages/dashboards/Widgets/Data/GenericChartDataSingleDataset";
// Declaring props types for ReportsBarChart
interface Props {
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark";
title: string;
description?: string | ReactNode;
date: string;
chart: {
labels: string[];
datasets: {
label: string;
data: number[];
};
};
[key: string]: any;
///////////////////////////
// options for bar chart //
///////////////////////////
const options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
interaction: {
intersect: false,
mode: "index",
},
scales: {
y: {
grid: {
drawBorder: false,
display: true,
drawOnChartArea: true,
drawTicks: false,
borderDash: [5, 5],
color: "rgba(255, 255, 255, .2)",
},
ticks: {
suggestedMin: 0,
suggestedMax: 500,
beginAtZero: true,
padding: 10,
font: {
size: 14,
weight: 300,
family: "Roboto",
style: "normal",
lineHeight: 2,
},
color: "#fff",
},
},
x: {
grid: {
drawBorder: false,
display: true,
drawOnChartArea: true,
drawTicks: false,
borderDash: [5, 5],
color: "rgba(255, 255, 255, .2)",
},
ticks: {
display: true,
color: "#f8f9fa",
padding: 10,
font: {
size: 14,
weight: 300,
family: "Roboto",
style: "normal",
lineHeight: 2,
},
},
},
},
};
////////////////////////////////////
// define properties and defaults //
////////////////////////////////////
interface Props
{
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark";
title: string;
description?: string;
date: string;
data: GenericChartDataSingleDataset;
}
function BarChart({color, title, description, date, chart}: Props): JSX.Element
BarChart.defaultProps = {
color: "dark",
description: "",
};
function getChartData(labels: any, dataset: any)
{
const {data, options} = configs(chart.labels || [], chart.datasets || {});
return {
chartData: {
labels,
datasets: [
{
label: dataset?.label,
tension: 0.4,
borderWidth: 0,
borderRadius: 4,
borderSkipped: false,
backgroundColor: "rgba(255, 255, 255, 0.8)",
data: dataset?.data,
maxBarThickness: 6,
},
],
}
};
}
function BarChart({color, title, description, date, data}: Props): JSX.Element
{
/////////////////////////////////////////////////////////
// enrich data with expected customizations and styles //
/////////////////////////////////////////////////////////
const {chartData} = getChartData(data?.labels, data?.dataset);
return (
<Card sx={{height: "100%"}}>
@ -63,17 +156,17 @@ function BarChart({color, title, description, date, chart}: Props): JSX.Element
mt={-5}
height="12.5rem"
>
<Bar data={data} options={options} />
<Bar data={chartData} options={options} />
</MDBox>
),
[chart, color]
[data, color]
)}
<MDBox pt={3} pb={1} px={1}>
<MDTypography variant="h6" textTransform="capitalize">
{title}
</MDTypography>
<MDTypography component="div" variant="button" color="text" fontWeight="light">
{description}
{parse(description)}
</MDTypography>
<Divider />
<MDBox display="flex" alignItems="center">
@ -90,10 +183,4 @@ function BarChart({color, title, description, date, chart}: Props): JSX.Element
);
}
// Setting default values for the props of ReportsBarChart
BarChart.defaultProps = {
color: "dark",
description: "",
};
export default BarChart;

View File

@ -19,10 +19,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
function configs(labels: any, datasets: any)
function configs(labels: any, datasets: any)
{
return {
data: {
dataderp: {
labels,
datasets: [
{

View File

@ -1,87 +0,0 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import DefaultCell from "layouts/dashboards/sales/components/DefaultCell";
import ProductCell from "layouts/dashboards/sales/components/ProductCell";
import RefundsCell from "layouts/dashboards/sales/components/RefundsCell";
import axlehire from "qqq/images/carrier-logos/axlehire.png"
import cdl from "qqq/images/carrier-logos/cdl.png"
import dhl from "qqq/images/carrier-logos/dhl.png"
import fedex from "qqq/images/carrier-logos/fedex.png"
import lso from "qqq/images/carrier-logos/lso.png"
import ontrac from "qqq/images/carrier-logos/ontrac.png"
import ups from "qqq/images/carrier-logos/ups.png"
const carrierSpendData = {
columns: [
{Header: "carrier", accessor: "product", width: "55%"},
{Header: "total YTD", accessor: "value"},
{Header: "monthly average", accessor: "adsSpent", align: "center"},
{Header: "service failures", accessor: "refunds", align: "center"},
],
rows: [
{
product: <ProductCell image={axlehire} name="AxleHire" orders="921" />,
value: <DefaultCell>$140,925</DefaultCell>,
adsSpent: <DefaultCell>$24,531</DefaultCell>,
refunds: <RefundsCell value={121} icon={{color: "success", name: "keyboard_arrow_up"}} />,
},
{
product: <ProductCell image={cdl} name="CDL" orders="2,421" />,
value: <DefaultCell>$40,600</DefaultCell>,
adsSpent: <DefaultCell>$9,430</DefaultCell>,
refunds: <RefundsCell value={54} icon={{color: "success", name: "keyboard_arrow_up"}} />,
},
{
product: <ProductCell image={dhl} name="DHL" orders="1,391" />,
value: <DefaultCell>$90,233</DefaultCell>,
adsSpent: <DefaultCell>$18.30</DefaultCell>,
refunds: <RefundsCell value={54} icon={{color: "success", name: "keyboard_arrow_up"}} />,
},
{
product: <ProductCell image={fedex} name="FedEx" orders="12,821" />,
value: <DefaultCell>$80,250</DefaultCell>,
adsSpent: <DefaultCell>$4,200</DefaultCell>,
refunds: <RefundsCell value={40} icon={{color: "error", name: "keyboard_arrow_down"}} />,
},
{
product: <ProductCell image={lso} name="LSO" orders="5,921" />,
value: <DefaultCell>$91,300</DefaultCell>,
adsSpent: <DefaultCell>$7,364</DefaultCell>,
refunds: <RefundsCell value={5} icon={{color: "error", name: "keyboard_arrow_down"}} />,
},
{
product: <ProductCell image={ontrac} name="OnTrac" orders="5,921" />,
value: <DefaultCell>$77,300</DefaultCell>,
adsSpent: <DefaultCell>$4,064</DefaultCell>,
refunds: <RefundsCell value={5} icon={{color: "error", name: "keyboard_arrow_down"}} />,
},
{
product: <ProductCell image={ups} name="UPS" orders="8,232" />,
value: <DefaultCell>$130,992</DefaultCell>,
adsSpent: <DefaultCell>$9,500</DefaultCell>,
refunds: <RefundsCell value={13} icon={{color: "success", name: "keyboard_arrow_up"}} />,
},
],
};
export default carrierSpendData;

View File

@ -1,75 +0,0 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
interface Types {
labels: string[];
datasets: {
label: string;
color: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
data: number[];
}[];
}
const carrierVolumeLineChartData: Types = {
labels: ["Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [
{
label: " AxleHire",
color: "dark",
data: [500, 200, 110, 150, 440, 670, 100, 150, 300],
},
{
label: " CDL",
color: "info",
data: [1000, 3000, 4000, 1200, 1500, 2200, 2800, 3500, 4500],
},
{
label: " DHL",
color: "primary",
data: [3489, 5932, 4332, 8234, 9239, 10823, 9483, 11909, 11808],
},
{
label: " FedEx",
color: "success",
data: [20388, 21008, 19323, 17934, 18399, 22090, 23909, 25800, 28833],
},
{
label: " LSO",
color: "error",
data: [100, 300, 400, 1200, 1500, 2200, 2800, 2500, 2800],
},
{
label: " OnTrac",
color: "secondary",
data: [3489, 5932, 4332, 8234, 9239, 10823, 9483, 11909, 11808],
},
{
label: " UPS",
color: "warning",
data: [19348, 18008, 20844, 16034, 24000, 23480, 26809, 27888, 27909],
},
],
};
"warning"
export default carrierVolumeLineChartData;

View File

@ -19,9 +19,17 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const shipmentsByDayBarChartData = {
labels: ["M", "T", "W", "T", "F", "S", "S"],
datasets: {label: "Sales", data: [503, 202, 1001, 354, 659, 938, 350]},
};
export default shipmentsByDayBarChartData;
//////////////////////////////////////
// structure of expected chart data //
//////////////////////////////////////
export interface GenericChartData
{
description?: string;
labels: string[];
datasets: {
label: string;
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
data: number[];
}[];
}

View File

@ -19,10 +19,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const shipmentsByMonthLineChartData =
{
labels: ["Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: {label: "Mobile apps", data: [50, 40, 300, 320, 500, 350, 200, 230, 500]},
};
export default shipmentsByMonthLineChartData;
//////////////////////////////////////
// structure of expected chart data //
//////////////////////////////////////
export interface GenericChartDataSingleDataset
{
labels: string[];
dataset: {
label: string;
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
data: number[];
};
}

View File

@ -1,36 +0,0 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import MDBadgeDot from "components/MDBadgeDot";
import MDBox from "components/MDBox";
const shipmentsByCarrierPieChartData = {
labels: [" AxleHire", " CDL", " DHL", " FedEx", " LSO", " OnTrac", " UPS"],
datasets: {
label: "Projects",
backgroundColors: ["dark", "info", "primary", "success", "error", "secondary", "warning"],
data: [523, 1139, 1933, 3248, 993, 103, 2439]
},
};
export default shipmentsByCarrierPieChartData;

View File

@ -0,0 +1,230 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Card from "@mui/material/Card";
import Icon from "@mui/material/Icon";
import React, {ReactNode, useMemo} from "react";
import {Line} from "react-chartjs-2";
import colors from "assets/theme/base/colors";
import MDBadgeDot from "qqq/components/Temporary/MDBadgeDot";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
//////////////////////////////////////////
// structure of default line chart data //
//////////////////////////////////////////
export interface DefaultLineChartData
{
labels: string[];
lineLabels?: string[];
datasets: {
label: string;
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
data: number[];
}[];
};
/////////////////////
// display options //
/////////////////////
const options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
interaction: {
intersect: false,
mode: "index",
},
scales: {
y: {
grid: {
drawBorder: false,
display: true,
drawOnChartArea: true,
drawTicks: false,
borderDash: [5, 5],
color: "#c1c4ce5c",
},
ticks: {
display: true,
padding: 10,
color: "#9ca2b7",
font: {
size: 14,
weight: 300,
family: "Roboto",
style: "normal",
lineHeight: 2,
},
},
},
x: {
grid: {
drawBorder: false,
display: true,
drawOnChartArea: true,
drawTicks: true,
borderDash: [5, 5],
color: "#c1c4ce5c",
},
ticks: {
display: true,
color: "#9ca2b7",
padding: 10,
font: {
size: 14,
weight: 300,
family: "Roboto",
style: "normal",
lineHeight: 2,
},
},
},
},
};
/////////////////////////
// inputs and defaults //
/////////////////////////
interface Props
{
icon?: {
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
component: ReactNode;
};
title?: string;
height?: string | number;
data: DefaultLineChartData;
[key: string]: any;
}
DefaultLineChart.defaultProps = {
icon: {color: "info", component: ""},
title: "",
height: "19.125rem",
};
function DefaultLineChart({icon, title, height, data}: Props): JSX.Element
{
const allBackgroundColors = ["info", "warning", "primary", "success", "error", "secondary", "dark"];
if (data && data.datasets)
{
data.datasets.forEach((ds, index) =>
{
// @ts-ignore
ds.color = allBackgroundColors[index];
});
}
const chartDatasets = data && data.datasets
? data.datasets.map((dataset) => ({
...dataset,
tension: 0,
pointRadius: 3,
borderWidth: 4,
backgroundColor: "transparent",
fill: true,
pointBackgroundColor: colors[dataset.color]
? colors[dataset.color || "dark"].main
: colors.dark.main,
borderColor: colors[dataset.color]
? colors[dataset.color || "dark"].main
: colors.dark.main,
maxBarThickness: 6,
}))
: [];
let fullData = {};
if (data)
{
fullData = {
labels: data.labels,
datasets: chartDatasets
};
}
const renderChart = (
<MDBox py={2} pr={2} pl={icon.component ? 1 : 2}>
{title ? (
<MDBox display="flex" px={0} pt={0}>
{icon.component && (
<MDBox
width="4rem"
height="4rem"
bgColor={icon.color || "info"}
variant="gradient"
coloredShadow={icon.color || "info"}
borderRadius="xl"
display="flex"
justifyContent="center"
alignItems="center"
color="white"
mt={-5}
mr={2}
>
<Icon fontSize="medium">{icon.component}</Icon>
</MDBox>
)}
<MDBox mt={icon.component ? -2 : 0}>
{title && <MDTypography variant="h6">{title}</MDTypography>}
<MDBox mb={2}>
<MDTypography component="div" variant="button" color="text">
<MDBox display="flex" justifyContent="space-between">
<MDBox display="flex" ml={-1}>
{
data && data.lineLabels ? (
(data.lineLabels.map((label: string, index: number) => (
<MDBox key={index}>
<MDBadgeDot color={allBackgroundColors[index]} size="sm" badgeContent={label} />
</MDBox>
)
))) : null
}
</MDBox>
</MDBox>
</MDTypography>
</MDBox>
</MDBox>
</MDBox>
) : null}
{useMemo(
() => (
<MDBox height={height}>
<Line data={fullData} options={options} />
</MDBox>
),
[data, height]
)}
</MDBox>
);
return title ? <Card>{renderChart}</Card> : renderChart;
}
export default DefaultLineChart;

View File

@ -26,8 +26,72 @@ import {Bar} from "react-chartjs-2";
import colors from "qqq/components/Temporary/colors";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
import configs from "qqq/pages/dashboards/Widgets/Configs/HorizontalBarChartConfigs"
import {GenericChartData} from "qqq/pages/dashboards/Widgets/Data/GenericChartData";
//////////////////
// configuation //
//////////////////
const options = {
indexAxis: "y",
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
scales: {
y: {
grid: {
drawBorder: false,
display: true,
drawOnChartArea: true,
drawTicks: false,
borderDash: [5, 5],
color: "#c1c4ce5c",
},
ticks: {
display: true,
padding: 10,
color: "#9ca2b7",
font: {
size: 14,
weight: 300,
family: "Roboto",
style: "normal",
lineHeight: 2,
},
},
},
x: {
grid: {
drawBorder: false,
display: false,
drawOnChartArea: true,
drawTicks: true,
color: "#c1c4ce5c",
},
ticks: {
display: true,
color: "#9ca2b7",
padding: 10,
font: {
size: 14,
weight: 300,
family: "Roboto",
style: "normal",
lineHeight: 2,
},
},
},
},
};
/////////////////////////
// inputs and defaults //
/////////////////////////
interface Props
{
icon?: {
@ -37,22 +101,15 @@ interface Props
title?: string;
description?: string | ReactNode;
height?: string | number;
chart: {
labels: string[];
datasets: {
label: string;
color: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
data: number[];
}[];
};
data: GenericChartData;
[key: string]: any;
}
function HorizontalBarChart({icon, title, description, height, chart}: Props): JSX.Element
function HorizontalBarChart({icon, title, description, height, data}: Props): JSX.Element
{
const chartDatasets = chart.datasets
? chart.datasets.map((dataset) => ({
const chartDatasets = data.datasets
? data.datasets.map((dataset) => ({
...dataset,
weight: 5,
borderWidth: 0,
@ -65,7 +122,14 @@ function HorizontalBarChart({icon, title, description, height, chart}: Props): J
}))
: [];
const {data, options} = configs(chart.labels || [], chartDatasets);
let fullData = {};
if (data)
{
fullData = {
labels: data.labels,
datasets: chartDatasets
};
}
const renderChart = (
<MDBox py={2} pr={2} pl={icon.component ? 1 : 2}>
@ -102,10 +166,10 @@ function HorizontalBarChart({icon, title, description, height, chart}: Props): J
{useMemo(
() => (
<MDBox height={height}>
<Bar data={data} options={options} />
<Bar data={fullData} options={options} />
</MDBox>
),
[chart, height]
[data, height]
)}
</MDBox>
);

View File

@ -21,32 +21,122 @@
import Card from "@mui/material/Card";
import Icon from "@mui/material/Icon";
import {useMemo, ReactNode} from "react";
import {ReactNode, useMemo} from "react";
import {Line} from "react-chartjs-2";
import colors from "qqq/components/Temporary/colors";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
import configs from "qqq/pages/dashboards/Widgets/Configs/LineChartConfigs";
interface Props {
icon?: {
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
component: ReactNode;
};
title?: string;
description?: string | ReactNode;
height?: string | number;
chart: {
labels: string[];
datasets: {
///////////////////////////////////////////
// structure of expected line chart data //
///////////////////////////////////////////
export interface LineChartData
{
labels: string[];
datasets: {
label: string;
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
data: number[];
}[];
};
[key: string]: any;
}[];
};
////////////////////////
// line chart options //
////////////////////////
const options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
interaction: {
intersect: false,
mode: "index",
},
scales: {
y: {
grid: {
drawBorder: false,
display: true,
drawOnChartArea: true,
drawTicks: false,
borderDash: [5, 5],
color: "rgba(255, 255, 255, .2)",
},
ticks: {
display: true,
color: "#f8f9fa",
padding: 10,
font: {
size: 14,
weight: 300,
family: "Roboto",
style: "normal",
lineHeight: 2,
},
},
},
x: {
grid: {
drawBorder: false,
display: false,
drawOnChartArea: false,
drawTicks: false,
borderDash: [5, 5],
},
ticks: {
display: true,
color: "#f8f9fa",
padding: 10,
font: {
size: 14,
weight: 300,
family: "Roboto",
style: "normal",
lineHeight: 2,
},
},
},
},
};
//////////////////////////////////////////
// define input properties and defaults //
//////////////////////////////////////////
interface Props
{
icon?: {
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
component: ReactNode;
};
title?: string;
description?: string | ReactNode;
height?: string | number;
chart: {
labels: string[];
datasets: {
label: string;
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
data: number[];
}[];
};
[key: string]: any;
}
LineChart.defaultProps = {
icon: {color: "info", component: ""},
title: "",
description: "",
height: "19.125rem",
};
function LineChart({icon, title, description, height, chart}: Props): JSX.Element
{
const chartDatasets = chart.datasets
@ -67,7 +157,7 @@ function LineChart({icon, title, description, height, chart}: Props): JSX.Elemen
}))
: [];
const {data, options} = configs(chart.labels || [], chartDatasets);
const {data} = configs(chart.labels || [], chartDatasets);
const renderChart = (
<MDBox py={2} pr={2} pl={icon.component ? 1 : 2}>
@ -115,11 +205,5 @@ function LineChart({icon, title, description, height, chart}: Props): JSX.Elemen
return title || description ? <Card>{renderChart}</Card> : renderChart;
}
LineChart.defaultProps = {
icon: {color: "info", component: ""},
title: "",
description: "",
height: "19.125rem",
};
export default LineChart;

View File

@ -22,22 +22,39 @@
import Card from "@mui/material/Card";
import Divider from "@mui/material/Divider";
import Icon from "@mui/material/Icon";
import parse from "html-react-parser";
import {ReactNode} from "react";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
interface Props {
image: string;
title: string;
description: string | ReactNode;
price: string;
location: ReactNode;
action?: ReactNode | boolean;
[key: string]: any;
//////////////////////////////////////////
// structure of location card data //
//////////////////////////////////////////
export interface LocationCardData
{
imageUrl: string;
title: string;
description: string;
footerText: string;
location: string;
}
function WarehouseCard({image, title, description, price, location, action}: Props): JSX.Element
interface Props
{
locationData: LocationCardData;
action?: ReactNode | boolean;
[key: string]: any;
}
LocationCard.defaultProps = {
action: false,
};
function LocationCard({locationData, action}: Props): JSX.Element
{
const {imageUrl, title, description, footerText, location} = locationData;
return (
<Card>
<MDBox
@ -50,7 +67,7 @@ function WarehouseCard({image, title, description, price, location, action}: Pro
>
<MDBox
component="img"
src={image}
src={imageUrl}
alt={title}
borderRadius="lg"
shadow="md"
@ -68,7 +85,7 @@ function WarehouseCard({image, title, description, price, location, action}: Pro
left={0}
top="0"
sx={{
backgroundImage: `url(${image})`,
backgroundImage: `url(${locationData.imageUrl})`,
transform: "scale(0.94)",
filter: "blur(12px)",
backgroundSize: "cover",
@ -83,7 +100,7 @@ function WarehouseCard({image, title, description, price, location, action}: Pro
{title}
</MDTypography>
<MDTypography variant="body2" color="text" sx={{mt: 1.5, mb: 1}}>
{description}
{parse(description)}
</MDTypography>
</MDBox>
<Divider />
@ -97,11 +114,11 @@ function WarehouseCard({image, title, description, price, location, action}: Pro
lineHeight={1}
>
<MDTypography variant="body2" fontWeight="regular" color="text">
{price}
{footerText}
</MDTypography>
<MDBox color="text" display="flex" alignItems="center">
<Icon color="inherit" sx={{m: 0.5}}>
place
place
</Icon>
<MDTypography variant="button" fontWeight="light" color="text">
{location}
@ -112,8 +129,4 @@ function WarehouseCard({image, title, description, price, location, action}: Pro
);
}
WarehouseCard.defaultProps = {
action: false,
};
export default WarehouseCard;
export default LocationCard;

View File

@ -21,11 +21,26 @@
import Card from "@mui/material/Card";
import Icon from "@mui/material/Icon";
import {useMemo, ReactNode} from "react";
import parse from "html-react-parser";
import {ReactNode, useMemo} from "react";
import {Pie} from "react-chartjs-2";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
import configs from "qqq/pages/dashboards/Widgets/Configs/PieChartConfigs"
import configs from "qqq/pages/dashboards/Widgets/Configs/PieChartConfigs";
//////////////////////////////////////////
// structure of expected bar chart data //
//////////////////////////////////////////
export interface PieChartData
{
labels: string[];
dataset: {
label: string;
backgroundColors?: string[];
data: number[];
};
}
// Declaring props types for PieChart
interface Props
@ -35,23 +50,16 @@ interface Props
component: ReactNode;
};
title?: string;
description?: string | ReactNode;
description?: string;
height?: string | number;
chart: {
labels: string[];
datasets: {
label: string;
backgroundColors: string[];
data: number[];
};
};
chart: PieChartData;
[key: string]: any;
}
function PieChart({icon, title, description, height, chart}: Props): JSX.Element
{
const {data, options} = configs(chart.labels || [], chart.datasets || {});
const {data, options} = configs(chart?.labels || [], chart?.dataset || {});
const renderChart = (
<MDBox py={2} pr={2} pl={icon.component ? 1 : 2}>
@ -79,7 +87,7 @@ function PieChart({icon, title, description, height, chart}: Props): JSX.Element
{title && <MDTypography variant="h6">{title}</MDTypography>}
<MDBox mb={2}>
<MDTypography component="div" variant="button" color="text">
{description}
{parse(description)}
</MDTypography>
</MDBox>
</MDBox>

View File

@ -22,61 +22,61 @@
import Card from "@mui/material/Card";
import Divider from "@mui/material/Divider";
import Grid from "@mui/material/Grid";
import {useMaterialUIController} from "context";
import parse from "html-react-parser";
import MDBadgeDot from "qqq/components/Temporary/MDBadgeDot";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
import shipmentsByCarrierPieChartData from "qqq/pages/dashboards/Widgets/Data/ShipmentsByCarrierPieChartData";
import PieChart from "qqq/pages/dashboards/Widgets/PieChart";
import PieChart, {PieChartData} from "qqq/pages/dashboards/Widgets/PieChart";
function ShipmentsByCarrierPieChart(): JSX.Element
// Declaring props types for PieChart
interface Props
{
const [controller] = useMaterialUIController();
const {darkMode} = controller;
title?: string;
description?: string;
data: PieChartData;
[key: string]: any;
}
function PieChartCard({title, description, data}: Props): JSX.Element
{
const allBackgroundColors = ["info", "warning", "primary", "success", "error", "secondary", "dark"];
if (data && data.dataset)
{
data.dataset.backgroundColors = allBackgroundColors;
}
return (
<Card sx={{height: "100%"}}>
<MDBox display="flex" justifyContent="space-between" alignItems="center" pt={2} px={2}>
<MDTypography variant="h6">Shipments By Carrier Year To Date</MDTypography>
<MDTypography variant="h6">{title}</MDTypography>
</MDBox>
<MDBox mt={3}>
<Grid container alignItems="center">
<Grid item xs={7}>
<PieChart chart={shipmentsByCarrierPieChartData} height="9.5rem" />
<PieChart chart={data} height="9.5rem" />
</Grid>
<Grid item xs={5}>
<MDBox pr={1}>
<MDBox>
<MDBadgeDot color="dark" size="sm" badgeContent="AxleHire" />
</MDBox>
<MDBox>
<MDBadgeDot color="info" size="sm" badgeContent="CDL" />
</MDBox>
<MDBox>
<MDBadgeDot color="primary" size="sm" badgeContent="DHL" />
</MDBox>
<MDBox>
<MDBadgeDot color="success" size="sm" badgeContent="FedEx" />
</MDBox>
<MDBox>
<MDBadgeDot color="error" size="sm" badgeContent="LSO" />
</MDBox>
<MDBox>
<MDBadgeDot color="secondary" size="sm" badgeContent="OnTrac" />
</MDBox>
<MDBox>
<MDBadgeDot color="warning" size="sm" badgeContent="UPS" />
</MDBox>
{
data && data.labels ? (
(data.labels.map((label: string, index: number) => (
<MDBox key={index}>
<MDBadgeDot color={allBackgroundColors[index]} size="sm" badgeContent={label} />
</MDBox>
)
))) : null
}
</MDBox>
</Grid>
</Grid>
<Divider />
<Grid container>
<Grid item xs={12}>
<MDBox pb={2} px={2} display="flex" flexDirection={{xs: "column", sm: "row"}} mt="auto" >
<MDBox pb={2} px={2} display="flex" flexDirection={{xs: "column", sm: "row"}} mt="auto">
<MDTypography variant="button" color="text" fontWeight="light">
<strong>Fedex and UPS</strong> delivered the majority of shipments with a combined percentage of <strong>55%</strong>.
The fewest shipments were delivered by <strong>AxleHire and OnTrac</strong> combining for <strong>6%</strong>.
{parse(description)}
</MDTypography>
</MDBox>
</Grid>
@ -86,4 +86,4 @@ function ShipmentsByCarrierPieChart(): JSX.Element
);
}
export default ShipmentsByCarrierPieChart;
export default PieChartCard;

View File

@ -22,30 +22,46 @@
import Card from "@mui/material/Card";
import Grid from "@mui/material/Grid";
import {ReactNode} from "react";
import {useMaterialUIController} from "context";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
import {StatisticsCardData} from "qqq/pages/dashboards/Widgets/StatisticsCard";
interface Props {
title: string;
count: string | number;
percentage?: {
color: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark" | "white";
value: string | number;
label: string;
};
dropdown?: {
action: (...args: any) => void;
menu: ReactNode;
value: string;
};
[key: string]: any;
interface Props
{
data: StatisticsCardData;
increaseIsGood: boolean;
dropdown?: {
action: (...args: any) => void;
menu: ReactNode;
value: string;
};
[key: string]: any;
}
function SimpleStatisticsCard({title, count, percentage, dropdown}: Props): JSX.Element
function SimpleStatisticsCard({data, increaseIsGood, dropdown}: Props): JSX.Element
{
const [controller] = useMaterialUIController();
const {darkMode} = controller;
const {title, count, percentageAmount, percentageLabel} = data;
let percentageString = "";
if (percentageAmount)
{
percentageString = percentageAmount.toLocaleString() + "%";
if (percentageAmount > 0)
{
percentageString = "+" + percentageString;
}
}
let percentColor: string;
if (increaseIsGood)
{
percentColor = (percentageAmount > 0) ? "success" : "warning";
}
else
{
percentColor = (percentageAmount < 0) ? "success" : "warning";
}
return (
<Card>
@ -63,17 +79,21 @@ function SimpleStatisticsCard({title, count, percentage, dropdown}: Props): JSX.
</MDTypography>
</MDBox>
<MDBox lineHeight={1}>
<MDTypography variant="h5" fontWeight="bold">
{count}
</MDTypography>
<MDTypography variant="button" fontWeight="bold" color={percentage.color}>
{percentage.value}&nbsp;
{
count ? (
<MDTypography variant="h5" fontWeight="bold">
{count.toLocaleString()}
</MDTypography>
) : null
}
<MDTypography variant="button" fontWeight="bold" color={percentColor}>
{percentageString}&nbsp;
<MDTypography
variant="button"
fontWeight="regular"
color={darkMode ? "text" : "secondary"}
color={"secondary"}
>
{percentage.label}
{percentageLabel}
</MDTypography>
</MDTypography>
</MDBox>

View File

@ -22,30 +22,42 @@
import Card from "@mui/material/Card";
import Divider from "@mui/material/Divider";
import Icon from "@mui/material/Icon";
import {useMemo, ReactNode} from "react";
import parse from "html-react-parser";
import {useMemo} from "react";
import {Line} from "react-chartjs-2";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
import configs from "qqq/pages/dashboards/Widgets/Configs/LineChartConfigs"
import configs from "qqq/pages/dashboards/Widgets/Configs/LineChartConfigs";
interface Props {
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark";
title: string;
description?: string | ReactNode;
date: string;
chart: {
labels: string[];
datasets: {
//////////////////////////////////////////
// structure of expected bar chart data //
//////////////////////////////////////////
export interface SmallLineChartData
{
labels: string[];
dataset: {
label: string;
data: number[];
};
};
[key: string]: any;
};
}
interface Props
{
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark";
title: string;
description?: string;
date: string;
chart: SmallLineChartData;
[key: string]: any;
}
function SmallLineChart({color, title, description, date, chart}: Props): JSX.Element
{
const {data, options} = configs(chart.labels || [], chart.datasets || {});
const {data, options} = configs(chart?.labels || [], chart?.dataset || {});
console.log(`DATA: ${JSON.stringify(data)}`);
return (
<Card sx={{height: "100%"}}>
@ -72,7 +84,7 @@ function SmallLineChart({color, title, description, date, chart}: Props): JSX.El
{title}
</MDTypography>
<MDTypography component="div" variant="button" color="text" fontWeight="light">
{description}
{parse(description)}
</MDTypography>
<Divider />
<MDBox display="flex" alignItems="center">

View File

@ -26,22 +26,67 @@ import {ReactNode} from "react";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
// Declaring props types for CompleStatisticsCard
interface Props {
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
title: string;
count: string | number;
percentage?: {
color: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark" | "white";
amount: string | number;
label: string;
};
icon: ReactNode;
[key: string]: any;
///////////////////////////////////////////
// structure of expected stats card data //
///////////////////////////////////////////
export interface StatisticsCardData
{
title: string;
count: number;
percentageAmount: number;
percentageLabel: string;
}
function StatisticsCard({color, title, count, percentage, icon}: Props): JSX.Element
/////////////////////////
// inputs and defaults //
/////////////////////////
interface Props
{
data: StatisticsCardData;
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
icon: ReactNode;
increaseIsGood: boolean;
dropdown?: {
action: (...args: any) => void;
menu: ReactNode;
value: string;
};
[key: string]: any;
}
StatisticsCard.defaultProps = {
color: "info",
increaseIsGood: true
};
function StatisticsCard({data, color, icon, increaseIsGood}: Props): JSX.Element
{
const {title, count, percentageAmount, percentageLabel} = data;
let percentageString = "";
if (percentageAmount)
{
percentageString = percentageAmount.toLocaleString() + "%";
if (percentageAmount > 0)
{
percentageString = "+" + percentageString;
}
}
let percentColor = "dark";
if (percentageAmount !== 0)
{
if (increaseIsGood)
{
percentColor = (percentageAmount > 0) ? "success" : "warning";
}
else
{
percentColor = (percentageAmount < 0) ? "success" : "warning";
}
}
return (
<Card>
<MDBox display="flex" justifyContent="space-between" pt={1} px={2}>
@ -66,34 +111,34 @@ function StatisticsCard({color, title, count, percentage, icon}: Props): JSX.Ele
<MDTypography variant="button" fontWeight="light" color="text">
{title}
</MDTypography>
<MDTypography variant="h4">{count}</MDTypography>
{
count !== undefined ? (
<MDTypography variant="h4">{count.toLocaleString()}</MDTypography>
) : null
}
</MDBox>
</MDBox>
<Divider />
<MDBox pb={2} px={2}>
<MDTypography component="p" variant="button" color="text" display="flex">
<MDTypography
component="span"
variant="button"
fontWeight="bold"
color={percentage.color}
>
{percentage.amount}
</MDTypography>
&nbsp;{percentage.label}
</MDTypography>
</MDBox>
{
percentageAmount !== undefined && percentageAmount !== 0 ? (
<MDBox pb={2} px={2}>
<MDTypography component="p" variant="button" color="text" display="flex">
<MDTypography
component="span"
variant="button"
fontWeight="bold"
color={percentColor}
>
{percentageString}
</MDTypography>
&nbsp;{percentageLabel}
</MDTypography>
</MDBox>
) : null
}
</Card>
);
}
StatisticsCard.defaultProps = {
color: "info",
percentage: {
color: "success",
text: "",
label: "",
},
};
export default StatisticsCard;

View File

@ -0,0 +1,142 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Icon} from "@mui/material";
import Card from "@mui/material/Card";
import Grid from "@mui/material/Grid";
import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
import React, {useEffect, useState} from "react";
import DataTable, {TableDataInput} from "qqq/components/Temporary/DataTable";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
/////////////////////////
// inputs and defaults //
/////////////////////////
interface Props
{
title: string;
data: TableDataInput;
dropdownOptions?: string[];
dropdownOnChange?: (selectedValue: string, widgetIndex: number) => void;
widgetIndex?: number;
[key: string]: any;
}
function TableCard({title, data, dropdownOptions, dropdownOnChange, widgetIndex}: Props): JSX.Element
{
const openArrowIcon = "arrow_drop_down";
const closeArrowIcon = "arrow_drop_up";
const [dropdown, setDropdown] = useState<string | null>(null);
const [dropdownValue, setDropdownValue] = useState<string>("");
const [dropdownIcon, setDropdownIcon] = useState<string>(openArrowIcon);
const openDropdown = ({currentTarget}: any) =>
{
setDropdown(currentTarget);
setDropdownIcon(closeArrowIcon);
};
const closeDropdown = ({currentTarget}: any) =>
{
setDropdown(null);
setDropdownValue(currentTarget.innerText || dropdownValue);
setDropdownIcon(openArrowIcon);
alert(widgetIndex);
dropdownOnChange(currentTarget.innerText || dropdownValue, widgetIndex);
};
const renderMenu = (state: any, open: any, close: any, icon: string) => (
dropdownOptions && (
<span style={{whiteSpace: "nowrap"}}>
<Icon onClick={open} fontSize={"medium"} style={{cursor: "pointer", float: "right"}}>{icon}</Icon>
<Menu
anchorEl={state}
transformOrigin={{vertical: "top", horizontal: "center"}}
open={Boolean(state)}
onClose={close}
keepMounted
disableAutoFocusItem
>
{
dropdownOptions.map((option) =>
<MenuItem key={option} onClick={close}>{option}</MenuItem>
)
}
</Menu>
</span>
)
);
useEffect(() =>
{
console.log(dropdownOptions);
if (dropdownOptions)
{
setDropdownValue(dropdownOptions[0]);
}
}, [dropdownOptions]);
return (
<Card>
<Grid container>
<Grid item xs={7}>
<MDBox pt={3} px={3}>
<MDTypography variant="h6" fontWeight="medium">
{title}
</MDTypography>
</MDBox>
</Grid>
<Grid item xs={5}>
{dropdownOptions && (
<MDBox p={2} width="100%" textAlign="right" lineHeight={1}>
<MDTypography
variant="caption"
color="secondary"
fontWeight="regular"
sx={{cursor: "pointer"}}
onClick={openDropdown}
>
{dropdownValue}
</MDTypography>
{renderMenu(dropdown, openDropdown, closeDropdown, dropdownIcon)}
</MDBox>
)}
</Grid>
</Grid>
<MDBox py={1}>
<DataTable
table={data}
entriesPerPage={false}
showTotalEntries={false}
isSorted={false}
noEndBorder
/>
</MDBox>
</Card>
);
}
export default TableCard;