mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-18 05:10:45 +00:00
QQQ-41: added app sections, wired all dashboards, implemented widgets that could be, upped version
This commit is contained in:
@ -19,35 +19,36 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Title} from "@mui/icons-material";
|
||||
import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
|
||||
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, {useState} from "react";
|
||||
import DefaultLineChart from "examples/Charts/LineCharts/DefaultLineChart";
|
||||
import DashboardLayout from "examples/LayoutContainers/DashboardLayout";
|
||||
import DataTable from "examples/Tables/DataTable";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import DashboardLayout from "qqq/components/DashboardLayout";
|
||||
import Footer from "qqq/components/Footer";
|
||||
import Navbar from "qqq/components/Navbar";
|
||||
import MDBadgeDot from "qqq/components/Temporary/MDBadgeDot";
|
||||
import {TableDataInput} from "qqq/components/Temporary/DataTable";
|
||||
import MDBox from "qqq/components/Temporary/MDBox";
|
||||
import MDTypography from "qqq/components/Temporary/MDTypography";
|
||||
import ShipmentsByWarehouseTable from "qqq/pages/dashboards/Tables/ShipmentsByWarehouseTable";
|
||||
import carrierSpendData from "qqq/pages/dashboards/Widgets/Data/CarrierSpendData";
|
||||
import carrierVolumeLineChartData from "qqq/pages/dashboards/Widgets/Data/CarrierVolumeLineChartData";
|
||||
import {GenericChartData} from "qqq/pages/dashboards/Widgets/Data/GenericChartData";
|
||||
import smallShipmentsByWarehouseData from "qqq/pages/dashboards/Widgets/Data/SmallShipmentsByWarehouseData";
|
||||
import timeInTransitBarChartData from "qqq/pages/dashboards/Widgets/Data/TimeInTransitBarChartData";
|
||||
import ShipmentsByCarrierPieChart from "qqq/pages/dashboards/Widgets/ShipmentsByChannelPieChart";
|
||||
import DefaultLineChart, {DefaultLineChartData} from "qqq/pages/dashboards/Widgets/DefaultLineChart";
|
||||
import HorizontalBarChart from "qqq/pages/dashboards/Widgets/HorizontalBarChart";
|
||||
import {PieChartData} from "qqq/pages/dashboards/Widgets/PieChart";
|
||||
import PieChartCard from "qqq/pages/dashboards/Widgets/PieChartCard";
|
||||
import SimpleStatisticsCard from "qqq/pages/dashboards/Widgets/SimpleStatisticsCard";
|
||||
import HorizontalBarChart from "./Widgets/HorizontalBarChart";
|
||||
import {StatisticsCardData} from "qqq/pages/dashboards/Widgets/StatisticsCard";
|
||||
import TableCard from "qqq/pages/dashboards/Widgets/TableCard";
|
||||
import QClient from "qqq/utils/QClient";
|
||||
|
||||
const qController = QClient.getInstance();
|
||||
|
||||
|
||||
function CarrierPerformance(): JSX.Element
|
||||
{
|
||||
const openArrowIcon = "arrow_drop_down";
|
||||
const closeArrowIcon = "arrow_drop_up";
|
||||
|
||||
const [shipmentsDropdownValue, setShipmentsDropdownValue] = useState<string>("Last 30 Days");
|
||||
const [deliveriesDropdownValue, setDeliveriesDropdownValue] = useState<string>("Last 30 Days");
|
||||
const [failuresDropdownValue, setFailuresDropdownValue] = useState<string>("Last 30 Days");
|
||||
@ -64,7 +65,7 @@ function CarrierPerformance(): JSX.Element
|
||||
{
|
||||
setShipmentsDropdown(currentTarget);
|
||||
setShipmentsDropdownIcon(closeArrowIcon);
|
||||
}
|
||||
};
|
||||
const closeShipmentsDropdown = ({currentTarget}: any) =>
|
||||
{
|
||||
setShipmentsDropdown(null);
|
||||
@ -74,8 +75,8 @@ function CarrierPerformance(): JSX.Element
|
||||
const openDeliveriesDropdown = ({currentTarget}: any) =>
|
||||
{
|
||||
setDeliveriesDropdown(currentTarget);
|
||||
setDeliveriesDropdownIcon(closeArrowIcon)
|
||||
}
|
||||
setDeliveriesDropdownIcon(closeArrowIcon);
|
||||
};
|
||||
const closeDeliveriesDropdown = ({currentTarget}: any) =>
|
||||
{
|
||||
setDeliveriesDropdown(null);
|
||||
@ -85,8 +86,8 @@ function CarrierPerformance(): JSX.Element
|
||||
const openFailuresDropdown = ({currentTarget}: any) =>
|
||||
{
|
||||
setFailuresDropdown(currentTarget);
|
||||
setFailuresDropdownIcon(closeArrowIcon)
|
||||
}
|
||||
setFailuresDropdownIcon(closeArrowIcon);
|
||||
};
|
||||
const closeFailuresDropdown = ({currentTarget}: any) =>
|
||||
{
|
||||
setFailuresDropdown(null);
|
||||
@ -94,7 +95,140 @@ function CarrierPerformance(): JSX.Element
|
||||
setFailuresDropdownIcon(openArrowIcon);
|
||||
};
|
||||
|
||||
// Dropdown menu template for the DefaultStatisticsCard
|
||||
|
||||
const [totalShipmentsData, setTotalShipmentsData] = useState({} as StatisticsCardData);
|
||||
const [successfulDeliveriesData, setSuccessfulDeliveriesData] = useState({} as StatisticsCardData);
|
||||
const [serviceFailuresData, setServiceFailuresData] = useState({} as StatisticsCardData);
|
||||
|
||||
const [shipmentsByCarrierTitle, setShipmentsByCarrierTitle] = useState("");
|
||||
const [shipmentsByCarrierDescription, setShipmentsByCarrierDescription] = useState("");
|
||||
const [shipmentsByCarrierData, setShipmentsByCarrierData] = useState({} as PieChartData);
|
||||
|
||||
const [carrierVolumeTitle, setCarrierVolumeTitle] = useState("");
|
||||
const [carrierVolumeData, setCarrierVolumeData] = useState({} as DefaultLineChartData);
|
||||
|
||||
const [spendByCarrierTitle, setSpendByCarrierTitle] = useState("");
|
||||
const [spendByCarrierData, setSpendByCarrierData] = useState({columns: [], rows: []} as TableDataInput);
|
||||
|
||||
const [timeInTransitTitle, setTimeInTransitTitle] = useState("");
|
||||
const [timeInTransitData, setTimeInTransitData] = useState({} as GenericChartData);
|
||||
|
||||
const [qInstance, setQInstance] = useState(null as QInstance);
|
||||
const [dataLoaded, setDataLoaded] = useState(false);
|
||||
|
||||
//////////////////////////
|
||||
// load meta data first //
|
||||
//////////////////////////
|
||||
useEffect(() =>
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const newQInstance = await qController.loadMetaData();
|
||||
setQInstance(newQInstance);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// once meta data has loaded, load widgets' data //
|
||||
///////////////////////////////////////////////////
|
||||
useEffect(() =>
|
||||
{
|
||||
if (!qInstance || dataLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
setDataLoaded(true);
|
||||
loadYTDShipmentsByCarrierData();
|
||||
loadTotalShipmentsData();
|
||||
loadSuccessfulDeliveriesData();
|
||||
loadServiceFailuresData();
|
||||
loadCarrierVolumeData();
|
||||
loadSpendByCarrierData();
|
||||
loadTimeInTransitData();
|
||||
|
||||
}, [qInstance]);
|
||||
|
||||
|
||||
function loadTotalShipmentsData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("TotalShipmentsStatisticsCard");
|
||||
setTotalShipmentsData(widgetData);
|
||||
})();
|
||||
}
|
||||
|
||||
function loadSuccessfulDeliveriesData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("SuccessfulDeliveriesStatisticsCard");
|
||||
setSuccessfulDeliveriesData(widgetData);
|
||||
})();
|
||||
}
|
||||
|
||||
function loadServiceFailuresData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("ServiceFailuresStatisticsCard");
|
||||
setServiceFailuresData(widgetData);
|
||||
})();
|
||||
}
|
||||
|
||||
function loadCarrierVolumeData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("CarrierVolumeLineChart");
|
||||
setCarrierVolumeTitle(widgetData.title);
|
||||
setCarrierVolumeData(widgetData.chartData);
|
||||
})();
|
||||
}
|
||||
|
||||
function loadYTDShipmentsByCarrierData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("YTDShipmentsByCarrierPieChart");
|
||||
setShipmentsByCarrierTitle(widgetData.title);
|
||||
setShipmentsByCarrierDescription(widgetData.description);
|
||||
setShipmentsByCarrierData(widgetData.chartData);
|
||||
})();
|
||||
}
|
||||
|
||||
function loadSpendByCarrierData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("YTDSpendByCarrierTable");
|
||||
setSpendByCarrierTitle(widgetData.title);
|
||||
setSpendByCarrierData(widgetData);
|
||||
})();
|
||||
}
|
||||
|
||||
function loadTimeInTransitData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("TimeInTransitBarChart");
|
||||
setTimeInTransitTitle(widgetData.title);
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// todo: need to make it so all charts can use multiple datasets //
|
||||
///////////////////////////////////////////////////////////////////
|
||||
const data = {
|
||||
labels: widgetData.chartData.labels,
|
||||
datasets: [
|
||||
widgetData.chartData.dataset
|
||||
]
|
||||
};
|
||||
setTimeInTransitData(data);
|
||||
})();
|
||||
}
|
||||
|
||||
const renderMenu = (state: any, open: any, close: any, icon: string) => (
|
||||
<span style={{whiteSpace: "nowrap"}}>
|
||||
<Icon onClick={open} fontSize={"medium"} style={{cursor: "pointer", float: "right"}}>{icon}</Icon>
|
||||
@ -121,13 +255,8 @@ function CarrierPerformance(): JSX.Element
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} sm={4}>
|
||||
<SimpleStatisticsCard
|
||||
title="total shipments"
|
||||
count="50,234"
|
||||
percentage={{
|
||||
color: "success",
|
||||
value: "+5%",
|
||||
label: "since last month",
|
||||
}}
|
||||
data={totalShipmentsData}
|
||||
increaseIsGood={true}
|
||||
dropdown={{
|
||||
action: openShipmentsDropdown,
|
||||
menu: renderMenu(shipmentsDropdown, openShipmentsDropdown, closeShipmentsDropdown, shipmentsDropdownIcon),
|
||||
@ -137,29 +266,20 @@ function CarrierPerformance(): JSX.Element
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={4}>
|
||||
<SimpleStatisticsCard
|
||||
title="Successful deliveries"
|
||||
count="49,234"
|
||||
percentage={{
|
||||
color: "success",
|
||||
value: "+12%",
|
||||
label: "since last month",
|
||||
}}
|
||||
data={successfulDeliveriesData}
|
||||
increaseIsGood={true}
|
||||
dropdown={{
|
||||
action: openDeliveriesDropdown,
|
||||
menu: renderMenu(deliveriesDropdown, openDeliveriesDropdown, closeDeliveriesDropdown, deliveriesDropdownIcon),
|
||||
value: deliveriesDropdownValue,
|
||||
}}
|
||||
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={4}>
|
||||
<SimpleStatisticsCard
|
||||
title="service failures"
|
||||
count="832"
|
||||
percentage={{
|
||||
color: "error",
|
||||
value: "+1.2%",
|
||||
label: "since last month",
|
||||
}}
|
||||
data={serviceFailuresData}
|
||||
increaseIsGood={false}
|
||||
dropdown={{
|
||||
action: openFailuresDropdown,
|
||||
menu: renderMenu(failuresDropdown, openFailuresDropdown, closeFailuresDropdown, failuresDropdownIcon),
|
||||
@ -171,54 +291,35 @@ function CarrierPerformance(): JSX.Element
|
||||
</MDBox>
|
||||
<MDBox mb={3}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} sm={6} lg={4}>
|
||||
<ShipmentsByCarrierPieChart />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} lg={8}>
|
||||
<DefaultLineChart
|
||||
title="Carrier Volume by Month"
|
||||
description={
|
||||
<MDBox display="flex" justifyContent="space-between">
|
||||
<MDBox display="flex" ml={-1}>
|
||||
<MDBadgeDot color="dark" size="sm" badgeContent="AxleHire" />
|
||||
<MDBadgeDot color="info" size="sm" badgeContent="CDL" />
|
||||
<MDBadgeDot color="primary" size="sm" badgeContent="DHL" />
|
||||
<MDBadgeDot color="success" size="sm" badgeContent="FedEx" />
|
||||
<MDBadgeDot color="error" size="sm" badgeContent="LSO" />
|
||||
<MDBadgeDot color="secondary" size="sm" badgeContent="OnTrac" />
|
||||
<MDBadgeDot color="warning" size="sm" badgeContent="UPS" />
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
}
|
||||
chart={carrierVolumeLineChartData}
|
||||
title={carrierVolumeTitle}
|
||||
data={carrierVolumeData}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6} lg={4}>
|
||||
<MDBox mb={3}>
|
||||
<PieChartCard
|
||||
title={shipmentsByCarrierTitle}
|
||||
description={shipmentsByCarrierDescription}
|
||||
data={shipmentsByCarrierData}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</MDBox>
|
||||
<Grid container spacing={3} mb={3}>
|
||||
<Grid item xs={12}>
|
||||
<Card>
|
||||
<MDBox pt={3} px={3}>
|
||||
<MDTypography variant="h6" fontWeight="medium">
|
||||
Spend by Carrier YTD
|
||||
</MDTypography>
|
||||
</MDBox>
|
||||
<MDBox py={1}>
|
||||
<DataTable
|
||||
table={carrierSpendData}
|
||||
entriesPerPage={false}
|
||||
showTotalEntries={false}
|
||||
isSorted={false}
|
||||
noEndBorder
|
||||
/>
|
||||
</MDBox>
|
||||
</Card>
|
||||
<TableCard
|
||||
title={spendByCarrierTitle}
|
||||
data={spendByCarrierData}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<MDBox mb={3}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} lg={8}>
|
||||
<HorizontalBarChart title="Time in Transit Last 30 Days" chart={timeInTransitBarChartData} />
|
||||
<HorizontalBarChart height={250} title={timeInTransitTitle} data={timeInTransitData} />
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={4}>
|
||||
<ShipmentsByWarehouseTable title="Shipments by Warehouse" rows={smallShipmentsByWarehouseData} />
|
||||
|
@ -19,28 +19,215 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import Icon from "@mui/material/Icon";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import {useEffect, useState} from "react";
|
||||
import DashboardLayout from "qqq/components/DashboardLayout";
|
||||
import Footer from "qqq/components/Footer";
|
||||
import Navbar from "qqq/components/Navbar";
|
||||
import MDBox from "qqq/components/Temporary/MDBox";
|
||||
import MDTypography from "qqq/components/Temporary/MDTypography";
|
||||
import edisonWarehouse from "qqq/images/warehouses/edison_nj.jpg";
|
||||
import pattersonWarehouse from "qqq/images/warehouses/patterson.jpg";
|
||||
import stocktonWarehouse from "qqq/images/warehouses/stockton.jpg";
|
||||
import BarChart from "qqq/pages/dashboards/Widgets/BarChart";
|
||||
import shipmentsByDayBarChartData from "qqq/pages/dashboards/Widgets/Data/ShipmentsByDayBarChartData";
|
||||
import shipmentsByMonthLineChartData from "qqq/pages/dashboards/Widgets/Data/ShipmentsByMonthLineChartData";
|
||||
import ShipmentsByCarrierPieChart from "qqq/pages/dashboards/Widgets/ShipmentsByChannelPieChart";
|
||||
import {GenericChartDataSingleDataset} from "qqq/pages/dashboards/Widgets/Data/GenericChartDataSingleDataset";
|
||||
import LocationCard, {LocationCardData} from "qqq/pages/dashboards/Widgets/LocationCard";
|
||||
import {PieChartData} from "qqq/pages/dashboards/Widgets/PieChart";
|
||||
import PieChartCard from "qqq/pages/dashboards/Widgets/PieChartCard";
|
||||
import ShipmentsByWarehouse from "qqq/pages/dashboards/Widgets/ShipmentsByWarehouse";
|
||||
import SmallLineChart from "qqq/pages/dashboards/Widgets/SmallLineChart";
|
||||
import StatisticsCard from "qqq/pages/dashboards/Widgets/StatisticsCard";
|
||||
import WarehouseCard from "qqq/pages/dashboards/Widgets/WarehouseCard";
|
||||
import StatisticsCard, {StatisticsCardData} from "qqq/pages/dashboards/Widgets/StatisticsCard";
|
||||
import QClient from "qqq/utils/QClient";
|
||||
|
||||
const qController = QClient.getInstance();
|
||||
|
||||
function Overview(): JSX.Element
|
||||
{
|
||||
//////////////////////////////////
|
||||
// shipments by day widget data //
|
||||
//////////////////////////////////
|
||||
const [shipmentsByDayTitle, setShipmentsByDayTitle] = useState("");
|
||||
const [shipmentsByDayDescription, setShipmentsByDayDescription] = useState("");
|
||||
const [shipmentsByDayData, setShipmentsByDayData] = useState({} as GenericChartDataSingleDataset);
|
||||
|
||||
const [shipmentsByMonthTitle, setShipmentsByMonthTitle] = useState("");
|
||||
const [shipmentsByMonthDescription, setShipmentsByMonthDescription] = useState("");
|
||||
const [shipmentsByMonthData, setShipmentsByMonthData] = useState({} as GenericChartDataSingleDataset);
|
||||
|
||||
const [shipmentsByCarrierTitle, setShipmentsByCarrierTitle] = useState("");
|
||||
const [shipmentsByCarrierDescription, setShipmentsByCarrierDescription] = useState("");
|
||||
const [shipmentsByCarrierData, setShipmentsByCarrierData] = useState({} as PieChartData);
|
||||
|
||||
const [todaysShipmentsData, setTodaysShipmentsData] = useState({} as StatisticsCardData);
|
||||
const [shipmentsInTransitData, setShipmentsInTransitData] = useState({} as StatisticsCardData);
|
||||
const [openOrdersData, setOpenOrdersData] = useState({} as StatisticsCardData);
|
||||
const [shippingExceptionsData, setShippingExceptionsData] = useState({} as StatisticsCardData);
|
||||
|
||||
const [warehouseData, setWarehouseData] = useState([] as LocationCardData[]);
|
||||
|
||||
const [qInstance, setQInstance] = useState(null as QInstance);
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// load meta data first //
|
||||
//////////////////////////
|
||||
useEffect(() =>
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const newQInstance = await qController.loadMetaData();
|
||||
setQInstance(newQInstance);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// once meta data has loaded, load widgets' data //
|
||||
///////////////////////////////////////////////////
|
||||
useEffect(() =>
|
||||
{
|
||||
if (!qInstance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
loadShipmentsByDayData();
|
||||
loadShipmentsByMonthData();
|
||||
loadYTDShipmentsByCarrierData();
|
||||
|
||||
loadTodaysShipmentsData();
|
||||
loadShipmentsInTransitData();
|
||||
loadOpenOrdersData();
|
||||
loadShippingExceptionsData();
|
||||
|
||||
loadWarehouseData();
|
||||
|
||||
}, [qInstance]);
|
||||
|
||||
|
||||
function loadShipmentsByDayData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("TotalShipmentsByDayBarChart");
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// calculate average and number of days over that average //
|
||||
////////////////////////////////////////////////////////////
|
||||
let dataValues = widgetData.chartData.dataset.data;
|
||||
let totalShipments = 0;
|
||||
for (let i = 0; i < dataValues.length; i++)
|
||||
{
|
||||
totalShipments += dataValues[i];
|
||||
}
|
||||
|
||||
let daysOverAverage = 0;
|
||||
let average = Math.floor(totalShipments / 7);
|
||||
for (let i = 0; i < dataValues.length; i++)
|
||||
{
|
||||
if (dataValues[i] > average)
|
||||
{
|
||||
daysOverAverage++;
|
||||
}
|
||||
}
|
||||
|
||||
const description = "Over the last week there have been <strong>" + daysOverAverage.toLocaleString() + (daysOverAverage == 1 ? " day" : " days") + "</strong> with total shipments greater than the daily average of <strong>" + average.toLocaleString() + " shipments</strong>.";
|
||||
setShipmentsByDayTitle(widgetData.title);
|
||||
setShipmentsByDayData(widgetData.chartData);
|
||||
setShipmentsByDayDescription(description);
|
||||
})();
|
||||
}
|
||||
|
||||
function loadShipmentsByMonthData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("TotalShipmentsByMonthLineChart");
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// calculate if 'increasing or decreasing' //
|
||||
/////////////////////////////////////////////
|
||||
let dataValues = widgetData.chartData.dataset.data;
|
||||
let firstHalf = 0;
|
||||
let secondHalf = 0;
|
||||
for (let i = 0; i < dataValues.length; i++)
|
||||
{
|
||||
if (i < dataValues.length / 2)
|
||||
{
|
||||
firstHalf += dataValues[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
secondHalf += dataValues[i];
|
||||
}
|
||||
}
|
||||
|
||||
const description = "Total shipments have been <strong>" + ((secondHalf >= firstHalf) ? "increasing" : "decreasing") + "</strong> over the last eight months.";
|
||||
setShipmentsByMonthTitle(widgetData.title);
|
||||
setShipmentsByMonthDescription(description);
|
||||
setShipmentsByMonthData(widgetData.chartData);
|
||||
})();
|
||||
}
|
||||
|
||||
function loadYTDShipmentsByCarrierData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("YTDShipmentsByCarrierPieChart");
|
||||
setShipmentsByCarrierTitle(widgetData.title);
|
||||
setShipmentsByCarrierDescription(widgetData.description);
|
||||
setShipmentsByCarrierData(widgetData.chartData);
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
function loadTodaysShipmentsData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("TodaysShipmentsStatisticsCard");
|
||||
setTodaysShipmentsData(widgetData);
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
function loadShipmentsInTransitData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("ShipmentsInTransitStatisticsCard");
|
||||
setShipmentsInTransitData(widgetData);
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
function loadOpenOrdersData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("OpenOrdersStatisticsCard");
|
||||
setOpenOrdersData(widgetData);
|
||||
})();
|
||||
}
|
||||
|
||||
function loadShippingExceptionsData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("ShippingExceptionsStatisticsCard");
|
||||
setShippingExceptionsData(widgetData);
|
||||
})();
|
||||
}
|
||||
|
||||
function loadWarehouseData()
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const widgetData = await qController.widget("WarehouseLocationCards");
|
||||
setWarehouseData(widgetData);
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
const actionButtons = (
|
||||
<>
|
||||
<Tooltip title="Refresh" placement="bottom">
|
||||
@ -74,30 +261,30 @@ function Overview(): JSX.Element
|
||||
<MDBox mb={3}>
|
||||
<BarChart
|
||||
color="info"
|
||||
title="Total Shipments by Day"
|
||||
description={
|
||||
<span>Over the last week there have been <strong>3 days</strong> with total shipments <strong>greater than</strong> the daily average of <strong>564 shipments</strong>.</span>
|
||||
}
|
||||
title={shipmentsByDayTitle}
|
||||
description={shipmentsByDayDescription}
|
||||
date="Updated 3 minutes ago"
|
||||
chart={shipmentsByDayBarChartData}
|
||||
data={shipmentsByDayData}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6} lg={4}>
|
||||
<MDBox mb={3}>
|
||||
<ShipmentsByCarrierPieChart />
|
||||
<PieChartCard
|
||||
title={shipmentsByCarrierTitle}
|
||||
description={shipmentsByCarrierDescription}
|
||||
data={shipmentsByCarrierData}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6} lg={4}>
|
||||
<MDBox mb={3}>
|
||||
<SmallLineChart
|
||||
color="dark"
|
||||
title="shipments by month"
|
||||
description={
|
||||
<span>Total shipments have been <strong>increasing</strong> over the last eight months.</span>
|
||||
}
|
||||
date="Just updated"
|
||||
chart={shipmentsByMonthLineChartData}
|
||||
title={shipmentsByMonthTitle}
|
||||
description={shipmentsByMonthDescription}
|
||||
date="Just updatederp"
|
||||
chart={shipmentsByMonthData}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
@ -109,13 +296,8 @@ function Overview(): JSX.Element
|
||||
<MDBox mb={1.5}>
|
||||
<StatisticsCard
|
||||
icon="widgets"
|
||||
title="Today's Shipments"
|
||||
count="2,813"
|
||||
percentage={{
|
||||
color: "success",
|
||||
amount: "+15%",
|
||||
label: "than lask week",
|
||||
}}
|
||||
data={todaysShipmentsData}
|
||||
increaseIsGood={true}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
@ -123,13 +305,8 @@ function Overview(): JSX.Element
|
||||
<MDBox mb={1.5}>
|
||||
<StatisticsCard
|
||||
icon="local_shipping"
|
||||
title="Shipments In Transit"
|
||||
count="1,023"
|
||||
percentage={{
|
||||
color: "success",
|
||||
amount: "+1%",
|
||||
label: "than yesterday",
|
||||
}}
|
||||
data={shipmentsInTransitData}
|
||||
increaseIsGood={true}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
@ -138,13 +315,8 @@ function Overview(): JSX.Element
|
||||
<StatisticsCard
|
||||
color="warning"
|
||||
icon="receipt"
|
||||
title="Open Orders"
|
||||
count="213"
|
||||
percentage={{
|
||||
color: "error",
|
||||
amount: "+3%",
|
||||
label: "than last week",
|
||||
}}
|
||||
data={openOrdersData}
|
||||
increaseIsGood={true}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
@ -153,13 +325,8 @@ function Overview(): JSX.Element
|
||||
<StatisticsCard
|
||||
color="error"
|
||||
icon="error"
|
||||
title="Shipping Exceptions"
|
||||
count="28"
|
||||
percentage={{
|
||||
color: "success",
|
||||
amount: "-12%",
|
||||
label: "than yesterday",
|
||||
}}
|
||||
data={shippingExceptionsData}
|
||||
increaseIsGood={false}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
@ -167,48 +334,18 @@ function Overview(): JSX.Element
|
||||
</MDBox>
|
||||
<MDBox mt={2}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={6} lg={4}>
|
||||
<MDBox mt={3}>
|
||||
<WarehouseCard
|
||||
image={edisonWarehouse}
|
||||
title="Edison, NJ"
|
||||
description={
|
||||
<span>The Edison, NJ warehouse currently has <strong>38 open orders</strong> and <strong>39 ASNs</strong> are expected in the next week.</span>
|
||||
}
|
||||
price="99% SLA"
|
||||
location="Edison, NJ"
|
||||
action={actionButtons}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6} lg={4}>
|
||||
<MDBox mt={3}>
|
||||
<WarehouseCard
|
||||
image={pattersonWarehouse}
|
||||
title="Patterson, CA"
|
||||
description={
|
||||
<span>The Patterson, CA warehouse shipped <strong>32,032</strong> this year. The delivery SLA is <strong>97.3%</strong>, up <strong>0.8%</strong> from last week.</span>
|
||||
}
|
||||
price="98% SLA"
|
||||
location="Patterson, CA"
|
||||
action={actionButtons}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6} lg={4}>
|
||||
<MDBox mt={3}>
|
||||
<WarehouseCard
|
||||
image={stocktonWarehouse}
|
||||
title="Stockton, CA"
|
||||
description={
|
||||
<span>The Stockton, CA warehouse shipped <strong>2,032</strong> packages yesterday. Last week's failed shipments were down by <strong>12%</strong>.</span>
|
||||
}
|
||||
price="95% SLA"
|
||||
location="Stockton, CA"
|
||||
action={actionButtons}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
{
|
||||
warehouseData && warehouseData.map((data) => (
|
||||
<Grid item xs={12} md={6} lg={4} key={data.title}>
|
||||
<MDBox mt={3}>
|
||||
<LocationCard
|
||||
locationData={data}
|
||||
action={actionButtons}
|
||||
/>
|
||||
</MDBox>
|
||||
</Grid>
|
||||
))
|
||||
}
|
||||
</Grid>
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
|
57
src/qqq/pages/dashboards/Tables/ImageCell.tsx
Normal file
57
src/qqq/pages/dashboards/Tables/ImageCell.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
// Declaring props types for ProductCell
|
||||
import MDAvatar from "qqq/components/Temporary/MDAvatar";
|
||||
import MDBox from "qqq/components/Temporary/MDBox";
|
||||
import MDTypography from "qqq/components/Temporary/MDTypography";
|
||||
|
||||
interface Props
|
||||
{
|
||||
imageUrl: string;
|
||||
label: string;
|
||||
total?: string | number;
|
||||
totalType?: string;
|
||||
}
|
||||
|
||||
function ImageCell({imageUrl, label, total, totalType}: Props): JSX.Element
|
||||
{
|
||||
return (
|
||||
<MDBox display="flex" alignItems="center" pr={2}>
|
||||
<MDBox mr={2}>
|
||||
<MDAvatar src={imageUrl} alt={label} />
|
||||
</MDBox>
|
||||
<MDBox display="flex" flexDirection="column">
|
||||
<MDTypography variant="button" fontWeight="medium">
|
||||
{label}
|
||||
</MDTypography>
|
||||
<MDTypography variant="button" fontWeight="regular" color="secondary">
|
||||
<MDTypography component="span" variant="button" fontWeight="regular" color="success">
|
||||
{total}
|
||||
</MDTypography>{" "}
|
||||
{totalType}
|
||||
</MDTypography>
|
||||
</MDBox>
|
||||
</MDBox>
|
||||
);
|
||||
}
|
||||
|
||||
export default ImageCell;
|
@ -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;
|
||||
|
@ -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: [
|
||||
{
|
||||
|
@ -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;
|
@ -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;
|
@ -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[];
|
||||
}[];
|
||||
}
|
@ -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[];
|
||||
};
|
||||
}
|
@ -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;
|
230
src/qqq/pages/dashboards/Widgets/DefaultLineChart.tsx
Normal file
230
src/qqq/pages/dashboards/Widgets/DefaultLineChart.tsx
Normal 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;
|
@ -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>
|
||||
);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
@ -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>
|
||||
|
@ -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;
|
@ -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}
|
||||
{
|
||||
count ? (
|
||||
<MDTypography variant="h5" fontWeight="bold">
|
||||
{count.toLocaleString()}
|
||||
</MDTypography>
|
||||
) : null
|
||||
}
|
||||
<MDTypography variant="button" fontWeight="bold" color={percentColor}>
|
||||
{percentageString}
|
||||
<MDTypography
|
||||
variant="button"
|
||||
fontWeight="regular"
|
||||
color={darkMode ? "text" : "secondary"}
|
||||
color={"secondary"}
|
||||
>
|
||||
{percentage.label}
|
||||
{percentageLabel}
|
||||
</MDTypography>
|
||||
</MDTypography>
|
||||
</MDBox>
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
{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>
|
||||
{percentageLabel}
|
||||
</MDTypography>
|
||||
</MDBox>
|
||||
) : null
|
||||
}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
StatisticsCard.defaultProps = {
|
||||
color: "info",
|
||||
percentage: {
|
||||
color: "success",
|
||||
text: "",
|
||||
label: "",
|
||||
},
|
||||
};
|
||||
|
||||
export default StatisticsCard;
|
||||
|
142
src/qqq/pages/dashboards/Widgets/TableCard.tsx
Normal file
142
src/qqq/pages/dashboards/Widgets/TableCard.tsx
Normal 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;
|
Reference in New Issue
Block a user