diff --git a/client/package-lock.json b/client/package-lock.json index f94acbd..e55da04 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -11875,6 +11875,11 @@ "lodash": "^4.17.19" } }, + "react-csv": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/react-csv/-/react-csv-2.0.3.tgz", + "integrity": "sha512-exyAdFLAxtuM4wNwLYrlKyPYLiJ7e0mv9tqPAd3kq+k1CiJFtznevR3yP0icv5q/y200w+lzNgi7TQn1Wrhu0w==" + }, "react-dev-utils": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", diff --git a/client/package.json b/client/package.json index e2445b6..106834c 100644 --- a/client/package.json +++ b/client/package.json @@ -18,6 +18,7 @@ "react": "^17.0.2", "react-bootstrap": "^1.6.1", "react-chartjs-2": "^3.0.5", + "react-csv": "^2.0.3", "react-dom": "^17.0.2", "react-file-base64": "^1.0.3", "react-google-login": "^5.2.2", diff --git a/client/src/components/Ecommerce/CSVReportGeneration.js b/client/src/components/Ecommerce/CSVReportGeneration.js new file mode 100644 index 0000000..05f2ae9 --- /dev/null +++ b/client/src/components/Ecommerce/CSVReportGeneration.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { CSVLink } from 'react-csv'; + +function CSVReportGeneration({ data }) { + + const csv_data = data + const headers = [ + { label: "Date", key: "date" }, + { label: "Product ID", key: "product_id" }, + { label: "Product Name", key: "product_name" }, + { label: "Price/Per unit", key: "product_price" }, + { label: "Quantity", key: "product_qty" }, + { label: "Total", key: "total" }, + ] + + const csvReport = { + filename: 'SalesReport.csv', + headers, + data:csv_data + } + + + return ( +
+ Export to CSV +
+ ) +} + +export default CSVReportGeneration diff --git a/client/src/components/Ecommerce/Charts/SalesPieChart.js b/client/src/components/Ecommerce/Charts/SalesPieChart.js new file mode 100644 index 0000000..48ba83f --- /dev/null +++ b/client/src/components/Ecommerce/Charts/SalesPieChart.js @@ -0,0 +1,88 @@ +import React from 'react'; +import { Pie } from 'react-chartjs-2'; + +function SalesPieChart({ pie_data }) { + + + const dataLabel = [] + const dataValues = [] + + for (let pd of pie_data) { + const val = parseInt(pd.value) + dataLabel.push(pd.name) + dataValues.push(val) + } + + const bgColPalette = [ + 'rgba(255, 99, 132, 0.2)', //Red + 'rgba(54, 162, 235, 0.2)', //Blue + 'rgba(255, 206, 86, 0.2)', // Yellow + 'rgba(75, 192, 192, 0.2)', // Green + 'rgba(153, 102, 255, 0.2)', // Purple + 'rgba(255, 159, 64, 0.2)', // Orange + 'rgba(255, 99, 132, 0.8)', //Red + 'rgba(54, 162, 235, 0.8)', //Blue + 'rgba(255, 206, 86, 0.8)', // Yellow + 'rgba(75, 192, 192, 0.8)', // Green + 'rgba(153, 102, 255, 0.8)', // Purple + 'rgba(255, 159, 64, 0.8)', // Orange + 'rgba(255, 99, 132,1)', //Red + 'rgba(54, 162, 235, 1)', //Blue + 'rgba(255, 206, 86, 1)', // Yellow + 'rgba(75, 192, 192, 1)', // Green + 'rgba(153, 102, 255, 1)', // Purple + 'rgba(255, 159, 64, 1)', // Orange + ] + const borderColPalette = [ + 'rgba(255, 99, 132, 1)', + 'rgba(54, 162, 235, 1)', + 'rgba(255, 206, 86, 1)', + 'rgba(75, 192, 192, 1)', + 'rgba(153, 102, 255, 1)', + 'rgba(255, 159, 64, 1)', + 'rgba(255, 99, 132, 1)', + 'rgba(54, 162, 235, 1)', + 'rgba(255, 206, 86, 1)', + 'rgba(75, 192, 192, 1)', + 'rgba(153, 102, 255, 1)', + 'rgba(255, 159, 64, 1)', + 'rgba(255, 99, 132, 1)', + 'rgba(54, 162, 235, 1)', + 'rgba(255, 206, 86, 1)', + 'rgba(75, 192, 192, 1)', + 'rgba(153, 102, 255, 1)', + 'rgba(255, 159, 64, 1)', + ] + + + const background = [] + const border = [] + + for (let i = 0; i < pie_data.length; i++){ + background[i] = bgColPalette[i] + border[i] = borderColPalette[i] + } + + const data = { + labels: dataLabel, + datasets: [ + { + label: 'Contribution of each product', + data: dataValues, + backgroundColor:background , + borderColor:border, + borderWidth: 1, + }, + ], + + }; + + return ( + +
+ +
+ ) +} + +export default SalesPieChart diff --git a/client/src/components/Ecommerce/SaleDataCategory.js b/client/src/components/Ecommerce/SaleDataCategory.js index ab11a6a..059e1e0 100644 --- a/client/src/components/Ecommerce/SaleDataCategory.js +++ b/client/src/components/Ecommerce/SaleDataCategory.js @@ -17,7 +17,7 @@ const SaleDataCategory = ({onSelect,data}) => { return (
- {selectedItem ? items.find(item => item.id === selectedItem).label : "Select Blog Category"} + {selectedItem ? items.find(item => item.id === selectedItem).label : "Select Month"}
diff --git a/client/src/components/Ecommerce/Screen/ProductListScreen.js b/client/src/components/Ecommerce/Screen/ProductListScreen.js index 4b343ff..b7602df 100644 --- a/client/src/components/Ecommerce/Screen/ProductListScreen.js +++ b/client/src/components/Ecommerce/Screen/ProductListScreen.js @@ -79,15 +79,17 @@ function ProductListScreen({history}) { - Name - Price - Category - In Stock + Product ID + Name + Price + Category + In Stock {products.map(product=>( + {product._id} {product.name}  {product.price} {product.category} diff --git a/client/src/components/Ecommerce/Screen/SaleDataScreen.js b/client/src/components/Ecommerce/Screen/SaleDataScreen.js index 70e2fdd..7bc0f95 100644 --- a/client/src/components/Ecommerce/Screen/SaleDataScreen.js +++ b/client/src/components/Ecommerce/Screen/SaleDataScreen.js @@ -8,6 +8,8 @@ import BarChart from '../Charts/BarChart'; import LineChart from '../Charts/LineChart'; import MonthBarChart from '../Charts/MonthBarChart'; import ProductSaleBarChart from '../Charts/ProductSaleBarChart'; +import SalesPieChart from '../Charts/SalesPieChart'; +import CSVReportGeneration from '../CSVReportGeneration'; import { monthData } from "../EcommSeedData"; import SaleDataCategory from '../SaleDataCategory'; import Sidebar from '../Sidebar'; @@ -18,14 +20,14 @@ function SaleDataScreen({ history }) { const [monthSale, setMonthSale] = useState("") const [productSale, setProductSale] = useState("") const [search, setSearch] = useState("") + const [reportData, setReportData] = useState("") + const [salesPieData, setSalesPieData] = useState("") const dispatch = useDispatch() const { userInfo: { user,token } } = useSelector(state => state.userLogin) const order = useSelector(state => state.orderSaleData) - const { loading, error, orderSaleData } = order - - // if (orderSaleData) console.log(orderSaleData) + const { orderSaleData } = order useEffect(() => { @@ -38,7 +40,38 @@ function SaleDataScreen({ history }) { const handleSelect = (e) => { setGraphType(e) - + } + + const onSalesMonthSelect = (e) => { + const { totalOrder } = orderSaleData?.find(el => el.month === e) + const saleData = [] + const salesPieData = [] + + for (let data of totalOrder) { + for (let pd of data.orderedItems) { + const date = data.createdAt.substring(0, 10); + const product_id = pd._id; + const product_name = pd.name; + const product_price = pd.price; + const product_qty = pd.qty; + const total = pd.price * pd.qty + saleData.push({ date, product_id, product_name, product_price, product_qty, total }) + + // for pie chart + salesPieData.push({ name: product_name, value: total }) + + } + } + + // console.log(salesPieData); + + // for pie chart + const res = Array.from(salesPieData.reduce( + (m, { name, value }) => m.set(name, (m.get(name) || 0) + value), new + Map()), ([name, value]) => ({ name, value })); + + setSalesPieData(res) + setReportData(saleData) } const onMonthSelect = async (e) => { @@ -52,7 +85,6 @@ function SaleDataScreen({ history }) { } } const { data } = await axios.post(`/api/orders/saleDataByMonth`, { selectedMonth }, config) - setMonthSale(data) } catch (error) { @@ -72,7 +104,6 @@ function SaleDataScreen({ history }) { } } const { data } = await axios.post(`/api/orders/saleByAProduct`, {product_id:search }, config) - console.log(data); setProductSale(data) } catch (error) { @@ -121,7 +152,20 @@ function SaleDataScreen({ history }) {
- {productSale && } + {productSale && } + +
+

Sales Report Generation

+ + {reportData && } + {salesPieData && +
+

Contribution of sold products

+ +
+ } +
+ diff --git a/client/src/styles/ecommerce.css b/client/src/styles/ecommerce.css index d4a090b..ede16d6 100644 --- a/client/src/styles/ecommerce.css +++ b/client/src/styles/ecommerce.css @@ -243,3 +243,8 @@ main { min-width: 33% !important; margin-top: 1.5rem; } +.pie-heading { + text-align: center; + font-family: "Poppins"; + margin: 0.5rem 0 2rem 0; +} diff --git a/server/controller/orderController.js b/server/controller/orderController.js index 49674aa..89981df 100644 --- a/server/controller/orderController.js +++ b/server/controller/orderController.js @@ -110,17 +110,19 @@ const getSaleDataByYear = async (req, res) => { saleDataByMonths.push({ month, totalOrder: saleByMonth, numOfOrder: saleByMonth.length }) } + // New - const dd = new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 120).toISOString() + const numOfDays = 120 + const dd = new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * numOfDays).toISOString() - // console.log(dd.substring(0,10)) + console.log(dd.substring(0,10)) const test = [ // Get only records created in the last 30 days { $match: { "createdAt": { - // $gte: new Date(`${dd}`) - $gte: new Date(`${year}-07-01`), $lt: new Date(`${year}-07-31`) + $gte: new Date(`${dd.substring(0,10)}`) + // $gte: new Date(`${year}-07-01`), $lt: new Date(`${year}-07-31`) } } }, @@ -141,12 +143,14 @@ const getSaleDataByYear = async (req, res) => { ] - const dayCount = await Order.aggregate(test) - const dayWiseSale = new Array(30).fill(0) - - for (let i of dayCount) { - dayWiseSale[i.day]=dayWiseSale[i.day]+1 - } + // const dayCount = await Order.aggregate(test) + // console.log(dayCount) + // console.log(dayCount.length) + + // const dayWiseSale = new Array(30).fill(0) + // for (let i of dayCount) { + // dayWiseSale[i.day]=dayWiseSale[i.day]+1 + // } return res.status(200).json(saleDataByMonths)