@agilo/medusa-analytics-plugin 1.1.0 → 1.2.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -972,23 +972,23 @@ const PieChart = ({ data, dataKey }) => {
972
972
  )
973
973
  ] }) });
974
974
  };
975
- const columnHelper$1 = ui.createDataTableColumnHelper();
976
- const columns$1 = [
977
- columnHelper$1.accessor("sku", {
975
+ const columnHelper$3 = ui.createDataTableColumnHelper();
976
+ const columns$2 = [
977
+ columnHelper$3.accessor("sku", {
978
978
  header: "SKU",
979
979
  enableSorting: true,
980
980
  sortLabel: "SKU",
981
981
  sortAscLabel: "A-Z",
982
982
  sortDescLabel: "Z-A"
983
983
  }),
984
- columnHelper$1.accessor("variantName", {
984
+ columnHelper$3.accessor("variantName", {
985
985
  header: "Variant Name",
986
986
  enableSorting: true,
987
987
  sortLabel: "Variant Name",
988
988
  sortAscLabel: "A-Z",
989
989
  sortDescLabel: "Z-A"
990
990
  }),
991
- columnHelper$1.accessor("inventoryQuantity", {
991
+ columnHelper$3.accessor("inventoryQuantity", {
992
992
  header: "Inventory",
993
993
  enableSorting: true,
994
994
  sortLabel: "Inventory",
@@ -1000,10 +1000,10 @@ const columns$1 = [
1000
1000
  }
1001
1001
  })
1002
1002
  ];
1003
- const PAGE_SIZE = 10;
1003
+ const PAGE_SIZE$1 = 10;
1004
1004
  const ProductsTable = ({ products }) => {
1005
1005
  const [pagination, setPagination] = React__namespace.useState({
1006
- pageSize: PAGE_SIZE,
1006
+ pageSize: PAGE_SIZE$1,
1007
1007
  pageIndex: 0
1008
1008
  });
1009
1009
  const [search, setSearch] = React__namespace.useState("");
@@ -1034,7 +1034,7 @@ const ProductsTable = ({ products }) => {
1034
1034
  );
1035
1035
  }, [products, search, sorting, pagination]);
1036
1036
  const table = ui.useDataTable({
1037
- columns: columns$1,
1037
+ columns: columns$2,
1038
1038
  data: shownProducts,
1039
1039
  getRowId: (product) => product.sku,
1040
1040
  rowCount: products.length,
@@ -1069,10 +1069,10 @@ const ProductsTable = ({ products }) => {
1069
1069
  }
1070
1070
  }
1071
1071
  ),
1072
- products.length > PAGE_SIZE && /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Pagination, {})
1072
+ products.length > PAGE_SIZE$1 && /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Pagination, {})
1073
1073
  ] });
1074
1074
  };
1075
- const BACKEND_URL$1 = __BACKEND_URL__ === "/" ? "" : __BACKEND_URL__;
1075
+ const BACKEND_URL$2 = __BACKEND_URL__ === "/" ? "" : __BACKEND_URL__;
1076
1076
  async function retrieveProductAnalytics(date) {
1077
1077
  if (!date || !date.from || !(date == null ? void 0 : date.to)) {
1078
1078
  return void 0;
@@ -1080,7 +1080,7 @@ async function retrieveProductAnalytics(date) {
1080
1080
  const dateFrom = dateFns.format(date.from, "yyyy-MM-dd");
1081
1081
  const dateTo = dateFns.format(date.to, "yyyy-MM-dd");
1082
1082
  const data = await fetch(
1083
- `${BACKEND_URL$1}/admin/agilo-analytics/products?date_from=${dateFrom}&date_to=${dateTo}`
1083
+ `${BACKEND_URL$2}/admin/agilo-analytics/products?date_from=${dateFrom}&date_to=${dateTo}`
1084
1084
  );
1085
1085
  const productAnalytics = await data.json();
1086
1086
  return productAnalytics;
@@ -1095,11 +1095,11 @@ const useProductAnalytics = (query, options) => {
1095
1095
  ...options
1096
1096
  });
1097
1097
  };
1098
- const BACKEND_URL = __BACKEND_URL__ === "/" ? "" : __BACKEND_URL__;
1098
+ const BACKEND_URL$1 = __BACKEND_URL__ === "/" ? "" : __BACKEND_URL__;
1099
1099
  async function retrieveOrderAnalytics(preset, date) {
1100
1100
  if (!date || !date.from || !(date == null ? void 0 : date.to)) {
1101
1101
  const data2 = await fetch(
1102
- `${BACKEND_URL}/admin/agilo-analytics/orders?preset=${preset}`
1102
+ `${BACKEND_URL$1}/admin/agilo-analytics/orders?preset=${preset}`
1103
1103
  );
1104
1104
  const orderAnalytics2 = await data2.json();
1105
1105
  return orderAnalytics2;
@@ -1107,7 +1107,7 @@ async function retrieveOrderAnalytics(preset, date) {
1107
1107
  const dateFrom = dateFns.format(date.from, "yyyy-MM-dd");
1108
1108
  const dateTo = dateFns.format(date.to, "yyyy-MM-dd");
1109
1109
  const data = await fetch(
1110
- `${BACKEND_URL}/admin/agilo-analytics/orders?date_from=${dateFrom}&date_to=${dateTo}&preset=${preset}`
1110
+ `${BACKEND_URL$1}/admin/agilo-analytics/orders?date_from=${dateFrom}&date_to=${dateTo}&preset=${preset}`
1111
1111
  );
1112
1112
  const orderAnalytics = await data.json();
1113
1113
  return orderAnalytics;
@@ -1148,7 +1148,7 @@ const BarChartSkeleton = () => {
1148
1148
  const PieChartSkeleton = () => {
1149
1149
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full aspect-square max-h-[400px]", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-full" }) });
1150
1150
  };
1151
- const dummyData = [
1151
+ const dummyData$1 = [
1152
1152
  {
1153
1153
  a: "a",
1154
1154
  b: "b",
@@ -1180,27 +1180,209 @@ const dummyData = [
1180
1180
  c: 0
1181
1181
  }
1182
1182
  ];
1183
- const columnHelper = ui.createDataTableColumnHelper();
1184
- const columns = [
1185
- columnHelper.accessor("a", {
1183
+ const columnHelper$2 = ui.createDataTableColumnHelper();
1184
+ const columns$1 = [
1185
+ columnHelper$2.accessor("a", {
1186
1186
  header: () => null,
1187
1187
  cell: () => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-5" })
1188
1188
  }),
1189
- columnHelper.accessor("b", {
1189
+ columnHelper$2.accessor("b", {
1190
1190
  header: () => null,
1191
1191
  cell: () => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-5" })
1192
1192
  }),
1193
- columnHelper.accessor("c", {
1193
+ columnHelper$2.accessor("c", {
1194
1194
  header: () => null,
1195
1195
  cell: () => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-5" })
1196
1196
  })
1197
1197
  ];
1198
1198
  const ProductsTableSkeleton = () => {
1199
+ const [search, setSearch] = React__namespace.useState("");
1200
+ const table = ui.useDataTable({
1201
+ columns: columns$1,
1202
+ data: dummyData$1,
1203
+ getRowId: (product) => product.a,
1204
+ rowCount: dummyData$1.length,
1205
+ search: {
1206
+ state: search,
1207
+ onSearchChange: setSearch
1208
+ }
1209
+ });
1210
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.DataTable, { instance: table, children: [
1211
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Toolbar, { className: "px-0 pt-0", children: /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Search, { placeholder: "Search..." }) }),
1212
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Table, {})
1213
+ ] });
1214
+ };
1215
+ const BACKEND_URL = __BACKEND_URL__ === "/" ? "" : __BACKEND_URL__;
1216
+ async function retrieveCustomersAnalytics(date) {
1217
+ if (!date || !date.from || !(date == null ? void 0 : date.to)) {
1218
+ return void 0;
1219
+ }
1220
+ const dateFrom = dateFns.format(date.from, "yyyy-MM-dd");
1221
+ const dateTo = dateFns.format(date.to, "yyyy-MM-dd");
1222
+ const data = await fetch(
1223
+ `${BACKEND_URL}/admin/agilo-analytics/customers?date_from=${dateFrom}&date_to=${dateTo}`
1224
+ );
1225
+ const customersAnalytics = await data.json();
1226
+ return customersAnalytics;
1227
+ }
1228
+ const useCustomerAnalytics = (query, options) => {
1229
+ return reactQuery.useQuery({
1230
+ queryKey: ["customer-analytics", query == null ? void 0 : query.from, query == null ? void 0 : query.to],
1231
+ queryFn: async () => {
1232
+ const data = await retrieveCustomersAnalytics(query);
1233
+ return data;
1234
+ },
1235
+ ...options
1236
+ });
1237
+ };
1238
+ const StackedBarChart = ({
1239
+ data,
1240
+ xAxisDataKey,
1241
+ yAxisTickFormatter,
1242
+ useStableColors = false,
1243
+ colorKeyField,
1244
+ dataKeys
1245
+ }) => {
1246
+ const isDark = useDarkMode();
1247
+ const colors = React__namespace.default.useMemo(() => {
1248
+ if (!useStableColors || !data || !colorKeyField) {
1249
+ return [];
1250
+ }
1251
+ return generateColorsForData(data, colorKeyField, 70, isDark ? 60 : 50);
1252
+ }, [data, useStableColors, colorKeyField, isDark]);
1253
+ return /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { aspect: 16 / 9, children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.BarChart, { data, margin: { left: 20 }, children: [
1254
+ /* @__PURE__ */ jsxRuntime.jsx(
1255
+ recharts.CartesianGrid,
1256
+ {
1257
+ strokeDasharray: "3 3",
1258
+ stroke: isDark ? "#374151" : "#E5E7EB"
1259
+ }
1260
+ ),
1261
+ /* @__PURE__ */ jsxRuntime.jsx(
1262
+ recharts.XAxis,
1263
+ {
1264
+ dataKey: String(xAxisDataKey),
1265
+ tick: { fill: isDark ? "#D1D5DB" : "#6B7280" },
1266
+ axisLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
1267
+ tickLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
1268
+ tickMargin: 10
1269
+ }
1270
+ ),
1271
+ /* @__PURE__ */ jsxRuntime.jsx(
1272
+ recharts.YAxis,
1273
+ {
1274
+ tickFormatter: yAxisTickFormatter,
1275
+ allowDecimals: false,
1276
+ tick: { fill: isDark ? "#D1D5DB" : "#6B7280" },
1277
+ axisLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
1278
+ tickLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" }
1279
+ }
1280
+ ),
1281
+ /* @__PURE__ */ jsxRuntime.jsx(
1282
+ recharts.Tooltip,
1283
+ {
1284
+ cursor: {
1285
+ fill: isDark ? "rgba(55, 65, 81, 0.2)" : "rgba(243, 244, 246, 0.5)"
1286
+ },
1287
+ formatter: (value) => yAxisTickFormatter ? yAxisTickFormatter(value) : value,
1288
+ contentStyle: {
1289
+ backgroundColor: isDark ? "#1F2937" : "#FFFFFF",
1290
+ border: `1px solid ${isDark ? "#374151" : "#E5E7EB"}`,
1291
+ borderRadius: "0.5rem",
1292
+ color: isDark ? "#F9FAFB" : "#111827",
1293
+ boxShadow: isDark ? "0 4px 6px -1px rgba(0, 0, 0, 0.3)" : "0 4px 6px -1px rgba(0, 0, 0, 0.1)"
1294
+ },
1295
+ labelStyle: {
1296
+ color: isDark ? "#F9FAFB" : "#111827",
1297
+ fontWeight: "500",
1298
+ marginBottom: "4px"
1299
+ }
1300
+ }
1301
+ ),
1302
+ dataKeys == null ? void 0 : dataKeys.map((key, index) => /* @__PURE__ */ jsxRuntime.jsx(
1303
+ recharts.Bar,
1304
+ {
1305
+ dataKey: String(key),
1306
+ stackId: "a",
1307
+ fill: useStableColors && colors.length > 0 ? colors[index] : "#3B82F6"
1308
+ },
1309
+ String(key)
1310
+ ))
1311
+ ] }) });
1312
+ };
1313
+ const dummyData = [
1314
+ {
1315
+ a: "a",
1316
+ b: "b",
1317
+ c: 0,
1318
+ d: 0,
1319
+ e: /* @__PURE__ */ new Date()
1320
+ },
1321
+ {
1322
+ a: "a",
1323
+ b: "b",
1324
+ c: 0,
1325
+ d: 0,
1326
+ e: /* @__PURE__ */ new Date()
1327
+ },
1328
+ {
1329
+ a: "a",
1330
+ b: "b",
1331
+ c: 0,
1332
+ d: 0,
1333
+ e: /* @__PURE__ */ new Date()
1334
+ },
1335
+ {
1336
+ a: "a",
1337
+ b: "b",
1338
+ c: 0,
1339
+ d: 0,
1340
+ e: /* @__PURE__ */ new Date()
1341
+ },
1342
+ {
1343
+ a: "a",
1344
+ b: "b",
1345
+ c: 0,
1346
+ d: 0,
1347
+ e: /* @__PURE__ */ new Date()
1348
+ },
1349
+ {
1350
+ a: "a",
1351
+ b: "b",
1352
+ c: 0,
1353
+ d: 0,
1354
+ e: /* @__PURE__ */ new Date()
1355
+ }
1356
+ ];
1357
+ const columnHelper$1 = ui.createDataTableColumnHelper();
1358
+ const columns = [
1359
+ columnHelper$1.accessor("a", {
1360
+ header: () => null,
1361
+ cell: () => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-5" })
1362
+ }),
1363
+ columnHelper$1.accessor("b", {
1364
+ header: () => null,
1365
+ cell: () => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-5" })
1366
+ }),
1367
+ columnHelper$1.accessor("c", {
1368
+ header: () => null,
1369
+ cell: () => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-5" })
1370
+ }),
1371
+ columnHelper$1.accessor("d", {
1372
+ header: () => null,
1373
+ cell: () => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-5" })
1374
+ }),
1375
+ columnHelper$1.accessor("e", {
1376
+ header: () => null,
1377
+ cell: () => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-5" })
1378
+ })
1379
+ ];
1380
+ const CustomersTableSkeleton = () => {
1199
1381
  const [search, setSearch] = React__namespace.useState("");
1200
1382
  const table = ui.useDataTable({
1201
1383
  columns,
1202
1384
  data: dummyData,
1203
- getRowId: (product) => product.a,
1385
+ getRowId: (customer) => customer.a,
1204
1386
  rowCount: dummyData.length,
1205
1387
  search: {
1206
1388
  state: search,
@@ -1212,6 +1394,140 @@ const ProductsTableSkeleton = () => {
1212
1394
  /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Table, {})
1213
1395
  ] });
1214
1396
  };
1397
+ const columnHelper = ui.createDataTableColumnHelper();
1398
+ const PAGE_SIZE = 10;
1399
+ const CustomersTable = ({
1400
+ customers,
1401
+ currencyCode
1402
+ }) => {
1403
+ const [pagination, setPagination] = React__namespace.useState({
1404
+ pageSize: PAGE_SIZE,
1405
+ pageIndex: 0
1406
+ });
1407
+ const [search, setSearch] = React__namespace.useState("");
1408
+ const [sorting, setSorting] = React__namespace.useState(
1409
+ null
1410
+ );
1411
+ const navigate = reactRouterDom.useNavigate();
1412
+ const shownCustomers = React__namespace.useMemo(() => {
1413
+ let filtered = customers.filter(
1414
+ (customer) => customer.name.toLowerCase().includes(search.toLowerCase()) || customer.email.toLowerCase().includes(search.toLowerCase())
1415
+ );
1416
+ if (sorting && sorting.id) {
1417
+ filtered = filtered.slice().sort((a, b) => {
1418
+ const aVal = a[sorting.id];
1419
+ const bVal = b[sorting.id];
1420
+ if (aVal < bVal) {
1421
+ return sorting.desc ? 1 : -1;
1422
+ }
1423
+ if (aVal > bVal) {
1424
+ return sorting.desc ? -1 : 1;
1425
+ }
1426
+ return 0;
1427
+ });
1428
+ }
1429
+ return filtered.slice(
1430
+ pagination.pageIndex * pagination.pageSize,
1431
+ (pagination.pageIndex + 1) * pagination.pageSize
1432
+ );
1433
+ }, [customers, search, sorting, pagination]);
1434
+ const columns2 = React__namespace.useMemo(
1435
+ () => [
1436
+ columnHelper.accessor("name", {
1437
+ header: "Name",
1438
+ enableSorting: true,
1439
+ sortLabel: "Name",
1440
+ sortAscLabel: "A-Z",
1441
+ sortDescLabel: "Z-A"
1442
+ }),
1443
+ columnHelper.accessor("email", {
1444
+ header: "Email",
1445
+ enableSorting: true,
1446
+ sortLabel: "Email",
1447
+ sortAscLabel: "A-Z",
1448
+ sortDescLabel: "Z-A"
1449
+ }),
1450
+ columnHelper.accessor("order_count", {
1451
+ header: "Order Count",
1452
+ enableSorting: true,
1453
+ sortLabel: "Order Count",
1454
+ sortAscLabel: "Low to High",
1455
+ sortDescLabel: "High to Low"
1456
+ }),
1457
+ columnHelper.accessor("sales", {
1458
+ header: "Total Sales",
1459
+ enableSorting: true,
1460
+ sortLabel: "Total Sales",
1461
+ sortAscLabel: "Low to High",
1462
+ sortDescLabel: "High to Low",
1463
+ cell: ({ getValue }) => {
1464
+ const sales = getValue();
1465
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { children: new Intl.NumberFormat("en-US", {
1466
+ style: "currency",
1467
+ currency: currencyCode || "EUR"
1468
+ }).format(sales || 0) });
1469
+ }
1470
+ }),
1471
+ columnHelper.accessor("groups", {
1472
+ header: "Groups",
1473
+ cell: ({ getValue }) => {
1474
+ const groups = getValue();
1475
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { children: groups.length ? groups.join(", ") : "No Group" });
1476
+ }
1477
+ }),
1478
+ columnHelper.accessor("last_order", {
1479
+ header: "Last Order",
1480
+ enableSorting: true,
1481
+ sortLabel: "Last Order",
1482
+ sortAscLabel: "Oldest to Newest",
1483
+ sortDescLabel: "Newest to Oldest",
1484
+ cell: ({ getValue }) => {
1485
+ const date = getValue();
1486
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { children: date ? dateFns.format(new Date(date), "MMM dd, yyyy") : "No orders yet" });
1487
+ }
1488
+ })
1489
+ ],
1490
+ [currencyCode]
1491
+ );
1492
+ const table = ui.useDataTable({
1493
+ columns: columns2,
1494
+ data: shownCustomers,
1495
+ getRowId: (customer) => customer.customer_id,
1496
+ rowCount: customers.length,
1497
+ search: {
1498
+ state: search,
1499
+ onSearchChange: setSearch
1500
+ },
1501
+ pagination: {
1502
+ state: pagination,
1503
+ onPaginationChange: setPagination
1504
+ },
1505
+ sorting: {
1506
+ state: sorting,
1507
+ onSortingChange: setSorting
1508
+ },
1509
+ onRowClick: (_, row) => {
1510
+ navigate(`/customers/${row.original.customer_id}`);
1511
+ }
1512
+ });
1513
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.DataTable, { instance: table, children: [
1514
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Toolbar, { className: "px-0 pt-0", children: /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Search, { placeholder: "Search..." }) }),
1515
+ /* @__PURE__ */ jsxRuntime.jsx(
1516
+ ui.DataTable.Table,
1517
+ {
1518
+ emptyState: {
1519
+ filtered: {
1520
+ heading: "No customers found"
1521
+ },
1522
+ empty: {
1523
+ heading: "No customers available"
1524
+ }
1525
+ }
1526
+ }
1527
+ ),
1528
+ customers.length > PAGE_SIZE && /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Pagination, {})
1529
+ ] });
1530
+ };
1215
1531
  function dateToCalendarDate(date) {
1216
1532
  return new $35ea8db9cb2ccb90$export$99faa760c7908e4f(
1217
1533
  date.getFullYear(),
@@ -1270,6 +1586,7 @@ const AnalyticsPage = () => {
1270
1586
  return void 0;
1271
1587
  }, [rangeParam]);
1272
1588
  const { data: products, isLoading: isLoadingProducts } = useProductAnalytics(date);
1589
+ const { data: customers, isLoading: isLoadingCustomers } = useCustomerAnalytics(date);
1273
1590
  const { data: orders, isLoading: isLoadingOrders } = useOrderAnalytics(
1274
1591
  ["this-month", "last-month", "last-3-months"].includes(rangeParam) ? rangeParam : "custom",
1275
1592
  date
@@ -1468,6 +1785,14 @@ const AnalyticsPage = () => {
1468
1785
  disabled: isLoadingOrders || isLoadingProducts,
1469
1786
  children: "Products"
1470
1787
  }
1788
+ ),
1789
+ /* @__PURE__ */ jsxRuntime.jsx(
1790
+ ui.Tabs.Trigger,
1791
+ {
1792
+ value: "customers",
1793
+ disabled: isLoadingOrders || isLoadingProducts,
1794
+ children: "Customers"
1795
+ }
1471
1796
  )
1472
1797
  ] }),
1473
1798
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-8", children: [
@@ -1635,6 +1960,100 @@ const AnalyticsPage = () => {
1635
1960
  )
1636
1961
  ] })
1637
1962
  ] })
1963
+ ] }),
1964
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.Content, { value: "customers", children: [
1965
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-md:flex-col gap-4 mb-4", children: [
1966
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 flex-1", children: [
1967
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "relative", children: [
1968
+ /* @__PURE__ */ jsxRuntime.jsx(icons.User, { className: "absolute right-6 top-4 text-ui-fg-muted" }),
1969
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: "Total Customers" }),
1970
+ isLoadingCustomers ? /* @__PURE__ */ jsxRuntime.jsx(SmallCardSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: (customers == null ? void 0 : customers.total_customers) || 0 }) })
1971
+ ] }),
1972
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "relative", children: [
1973
+ /* @__PURE__ */ jsxRuntime.jsx(icons.User, { className: "absolute right-6 top-4 text-ui-fg-muted" }),
1974
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: "New Customers" }),
1975
+ isLoadingCustomers ? /* @__PURE__ */ jsxRuntime.jsx(SmallCardSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: (customers == null ? void 0 : customers.new_customers) || 0 }) })
1976
+ ] })
1977
+ ] }),
1978
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 flex-1", children: [
1979
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "relative", children: [
1980
+ /* @__PURE__ */ jsxRuntime.jsx(icons.User, { className: "absolute right-6 text-ui-fg-muted top-4 size-[15px]" }),
1981
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: "Returning Customers" }),
1982
+ isLoadingCustomers ? /* @__PURE__ */ jsxRuntime.jsx(SmallCardSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: (customers == null ? void 0 : customers.returning_customers) || 0 }) })
1983
+ ] }),
1984
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "relative", children: [
1985
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChartNoAxesCombined, { className: "absolute right-6 top-4 text-ui-fg-muted" }),
1986
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: "Average Sales per Customer" }),
1987
+ isLoadingCustomers || isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(SmallCardSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: new Intl.NumberFormat("en-US", {
1988
+ currency: (customers == null ? void 0 : customers.currency_code) || "EUR",
1989
+ style: "currency"
1990
+ }).format(
1991
+ ((orders == null ? void 0 : orders.total_sales) || 0) / ((customers == null ? void 0 : customers.total_customers) || 0)
1992
+ ) }) })
1993
+ ] })
1994
+ ] })
1995
+ ] }),
1996
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-md:flex-col gap-4 mb-4", children: [
1997
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
1998
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "New vs. Returning Customers" }),
1999
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Distribution of new and returning customers in the selected period" }),
2000
+ isLoadingCustomers ? /* @__PURE__ */ jsxRuntime.jsx(BarChartSkeleton, {}) : (customers == null ? void 0 : customers.customer_count) && customers.customer_count.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
2001
+ StackedBarChart,
2002
+ {
2003
+ data: customers.customer_count,
2004
+ xAxisDataKey: "name",
2005
+ lineColor: "#82ca9d",
2006
+ useStableColors: true,
2007
+ colorKeyField: "returning_customers",
2008
+ dataKeys: ["new_customers", "returning_customers"]
2009
+ }
2010
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(
2011
+ ui.Text,
2012
+ {
2013
+ size: "small",
2014
+ className: "text-ui-fg-muted text-center",
2015
+ children: "No data available for the selected period."
2016
+ }
2017
+ )
2018
+ ] }) }),
2019
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
2020
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Top Customer Groups by Sales" }),
2021
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Sales breakdown by customer group in the selected period" }),
2022
+ isLoadingCustomers ? /* @__PURE__ */ jsxRuntime.jsx(BarChartSkeleton, {}) : (customers == null ? void 0 : customers.customer_group) && customers.customer_group.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
2023
+ BarChart,
2024
+ {
2025
+ data: customers.customer_group,
2026
+ xAxisDataKey: "name",
2027
+ lineColor: "#82ca9d",
2028
+ useStableColors: true,
2029
+ colorKeyField: "name",
2030
+ yAxisDataKey: "total",
2031
+ yAxisTickFormatter: (value) => new Intl.NumberFormat("en-US", {
2032
+ currency: customers.currency_code || "EUR",
2033
+ maximumFractionDigits: 0
2034
+ }).format(value)
2035
+ }
2036
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(
2037
+ ui.Text,
2038
+ {
2039
+ size: "small",
2040
+ className: "text-ui-fg-muted text-center",
2041
+ children: "No data available for the selected period."
2042
+ }
2043
+ )
2044
+ ] }) })
2045
+ ] }),
2046
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-4 max-xl:flex-col", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { children: [
2047
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Top Customers by Sales" }),
2048
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Customers by sales in the selected period" }),
2049
+ isLoadingCustomers ? /* @__PURE__ */ jsxRuntime.jsx(CustomersTableSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(
2050
+ CustomersTable,
2051
+ {
2052
+ customers: (customers == null ? void 0 : customers.customer_sales) || [],
2053
+ currencyCode: (customers == null ? void 0 : customers.currency_code) || "EUR"
2054
+ }
2055
+ )
2056
+ ] }) })
1638
2057
  ] })
1639
2058
  ] })
1640
2059
  ]