From 0dc6e967bb0d5caab236ac89ab532e6393677a03 Mon Sep 17 00:00:00 2001 From: efrilm Date: Fri, 26 Sep 2025 00:04:35 +0700 Subject: [PATCH] Sales Order Report --- .../apps/report/sales/sales-order/page.tsx | 19 ++++ src/views/apps/report/ReportSalesList.tsx | 5 ++ .../sales-order/ReportSalesOrderCard.tsx | 78 +++++++++++++++++ .../sales-order/ReportSalesOrderContent.tsx | 86 +++++++++++++++++++ 4 files changed, 188 insertions(+) create mode 100644 src/app/[lang]/(dashboard)/(private)/apps/report/sales/sales-order/page.tsx create mode 100644 src/views/apps/report/sales/sales-order/ReportSalesOrderCard.tsx create mode 100644 src/views/apps/report/sales/sales-order/ReportSalesOrderContent.tsx diff --git a/src/app/[lang]/(dashboard)/(private)/apps/report/sales/sales-order/page.tsx b/src/app/[lang]/(dashboard)/(private)/apps/report/sales/sales-order/page.tsx new file mode 100644 index 0000000..c03c974 --- /dev/null +++ b/src/app/[lang]/(dashboard)/(private)/apps/report/sales/sales-order/page.tsx @@ -0,0 +1,19 @@ +import ReportTitle from '@/components/report/ReportTitle' +import ReportSalesOrderContent from '@/views/apps/report/sales/sales-order/ReportSalesOrderContent' +import Grid from '@mui/material/Grid2' + +const SalesOrderReportPage = () => { + return ( + + + + + + + + z + + ) +} + +export default SalesOrderReportPage diff --git a/src/views/apps/report/ReportSalesList.tsx b/src/views/apps/report/ReportSalesList.tsx index 1c809f1..899bd8e 100644 --- a/src/views/apps/report/ReportSalesList.tsx +++ b/src/views/apps/report/ReportSalesList.tsx @@ -35,6 +35,11 @@ const ReportSalesList: React.FC = () => { title: 'Penjualan per Kategori Produk', iconClass: 'tabler-receipt-2', link: getLocalizedUrl(`/apps/report/sales/sales-product-category`, locale as Locale) + }, + { + title: 'Penjualan Pesanan', + iconClass: 'tabler-receipt-2', + link: getLocalizedUrl(`/apps/report/sales/sales-order`, locale as Locale) } // { // title: 'Penjualan Produk per Pelanggan', diff --git a/src/views/apps/report/sales/sales-order/ReportSalesOrderCard.tsx b/src/views/apps/report/sales/sales-order/ReportSalesOrderCard.tsx new file mode 100644 index 0000000..b407de8 --- /dev/null +++ b/src/views/apps/report/sales/sales-order/ReportSalesOrderCard.tsx @@ -0,0 +1,78 @@ +import Grid from '@mui/material/Grid2' +import type { UserDataType } from '@components/card-statistics/HorizontalWithSubtitle' +import HorizontalWithSubtitle from '@components/card-statistics/HorizontalWithSubtitle' +import { ProfitLossReport, SalesReport } from '@/types/services/analytic' + +// Utility functions +const formatIDR = (amount: number) => { + return new Intl.NumberFormat('id-ID', { + minimumFractionDigits: 0, + maximumFractionDigits: 0 + }).format(amount) +} + +const formatPercentage = (value: number) => { + return `${value.toFixed(1)}%` +} + +interface ReportSalesOrderCardProps { + sales: SalesReport | undefined +} + +const ReportSalesOrderCard = ({ sales }: ReportSalesOrderCardProps) => { + if (!sales) { + return null // Will be handled by parent loading state + } + + // Using actual data from API response with correct field names + const data: UserDataType[] = [ + { + title: 'Penjualan', + stats: formatIDR(sales.summary.total_sales), + avatarIcon: 'tabler-trending-up', + avatarColor: 'success', + trend: 'positive', + trendNumber: '', + subtitle: 'Total Penjualan' + }, + { + title: 'Total Pesanan', + stats: sales.summary.total_orders.toString(), + avatarIcon: 'tabler-gauge', + avatarColor: 'success', + trend: 'positive', + trendNumber: '', + subtitle: 'Total Pesanan' + }, + { + title: 'Rata Rata', + stats: formatIDR(sales.summary.average_order_value), + avatarIcon: 'tabler-trending-up', + avatarColor: sales.summary.average_order_value >= 0 ? 'success' : 'error', + trend: sales.summary.average_order_value >= 0 ? 'positive' : 'negative', + trendNumber: '', + subtitle: 'Rata Rata Nilai Pesanan' + }, + { + title: 'Penjualan Bersih', + stats: formatIDR(sales.summary.net_sales), + avatarIcon: sales.summary.net_sales >= 0 ? 'tabler-trending-up' : 'tabler-trending-down', + avatarColor: sales.summary.net_sales >= 0 ? 'success' : 'error', + trend: sales.summary.net_sales >= 0 ? 'positive' : 'negative', + trendNumber: '', + subtitle: 'Net Profit' + } + ] + + return ( + + {data.map((item, i) => ( + + + + ))} + + ) +} + +export default ReportSalesOrderCard diff --git a/src/views/apps/report/sales/sales-order/ReportSalesOrderContent.tsx b/src/views/apps/report/sales/sales-order/ReportSalesOrderContent.tsx new file mode 100644 index 0000000..20f91d4 --- /dev/null +++ b/src/views/apps/report/sales/sales-order/ReportSalesOrderContent.tsx @@ -0,0 +1,86 @@ +'use client' + +import DateRangePicker from '@/components/RangeDatePicker' +import { ReportItemHeader, ReportItemSubheader } from '@/components/report/ReportItem' +import { useSalesAnalytics } from '@/services/queries/analytics' +import { formatCurrency, formatDate, formatDateDDMMYYYY } from '@/utils/transform' +import { Button, Card, CardContent } from '@mui/material' +import { useState } from 'react' +import ReportSalesOrderCard from './ReportSalesOrderCard' + +const ReportSalesOrderContent = () => { + const [startDate, setStartDate] = useState(new Date()) + const [endDate, setEndDate] = useState(new Date()) + + const { data: sales } = useSalesAnalytics({ + date_from: formatDateDDMMYYYY(startDate!), + date_to: formatDateDDMMYYYY(endDate!) + }) + + return ( + <> + + + +
+
+ + +
+
+ + +
+ + + + + + + + + + + + + + {sales?.data?.map((c, index) => ( + + + + + + + + + + )) || []} + +
DatePenjualanPesananQtyPajakDiskonPendapatan
{formatDate(c.date)}{formatCurrency(c.sales)}{c.orders}{c.items}{formatCurrency(c.tax)}{formatCurrency(c.discount)} + {formatCurrency(c.net_sales)} +
+
+ +
+
+ + ) +} + +export default ReportSalesOrderContent