@agilo/medusa-analytics-plugin 1.0.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.
|
@@ -7,10 +7,10 @@ const icons = require("@medusajs/icons");
|
|
|
7
7
|
const lucideReact = require("lucide-react");
|
|
8
8
|
const dateFns = require("date-fns");
|
|
9
9
|
const reactAriaComponents = require("react-aria-components");
|
|
10
|
+
const reactRouterDom = require("react-router-dom");
|
|
10
11
|
const recharts = require("recharts");
|
|
11
12
|
const clsx = require("clsx");
|
|
12
13
|
const tailwindMerge = require("tailwind-merge");
|
|
13
|
-
const reactRouterDom = require("react-router-dom");
|
|
14
14
|
const reactQuery = require("@tanstack/react-query");
|
|
15
15
|
function _interopNamespace(e) {
|
|
16
16
|
if (e && e.__esModule) return e;
|
|
@@ -675,68 +675,65 @@ const LineChart = ({
|
|
|
675
675
|
const isDark = useDarkMode();
|
|
676
676
|
const isSingleDataPoint = data && data.length === 1;
|
|
677
677
|
if (isSingleDataPoint) {
|
|
678
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
679
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
{
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
fontWeight: "500",
|
|
725
|
-
marginBottom: "4px"
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
),
|
|
729
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
730
|
-
recharts.Bar,
|
|
731
|
-
{
|
|
732
|
-
dataKey: yAxisDataKey,
|
|
733
|
-
fill: lineColor,
|
|
734
|
-
radius: [4, 4, 0, 0],
|
|
735
|
-
maxBarSize: 60
|
|
678
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { aspect: 16 / 9, children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.BarChart, { data, margin: { left: 20 }, children: [
|
|
679
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
680
|
+
recharts.CartesianGrid,
|
|
681
|
+
{
|
|
682
|
+
strokeDasharray: "3 3",
|
|
683
|
+
stroke: isDark ? "#374151" : "#E5E7EB"
|
|
684
|
+
}
|
|
685
|
+
),
|
|
686
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
687
|
+
recharts.XAxis,
|
|
688
|
+
{
|
|
689
|
+
dataKey: xAxisDataKey,
|
|
690
|
+
tick: { fill: isDark ? "#D1D5DB" : "#6B7280" },
|
|
691
|
+
axisLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
|
|
692
|
+
tickLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
|
|
693
|
+
tickMargin: 10
|
|
694
|
+
}
|
|
695
|
+
),
|
|
696
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
697
|
+
recharts.YAxis,
|
|
698
|
+
{
|
|
699
|
+
tickFormatter: yAxisTickFormatter,
|
|
700
|
+
allowDecimals: false,
|
|
701
|
+
tick: { fill: isDark ? "#D1D5DB" : "#6B7280" },
|
|
702
|
+
axisLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
|
|
703
|
+
tickLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" }
|
|
704
|
+
}
|
|
705
|
+
),
|
|
706
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
707
|
+
recharts.Tooltip,
|
|
708
|
+
{
|
|
709
|
+
cursor: {
|
|
710
|
+
fill: isDark ? "rgba(55, 65, 81, 0.2)" : "rgba(243, 244, 246, 0.5)"
|
|
711
|
+
},
|
|
712
|
+
formatter: (value) => yAxisTickFormatter ? yAxisTickFormatter(value) : value,
|
|
713
|
+
contentStyle: {
|
|
714
|
+
backgroundColor: isDark ? "#1F2937" : "#FFFFFF",
|
|
715
|
+
border: `1px solid ${isDark ? "#374151" : "#E5E7EB"}`,
|
|
716
|
+
borderRadius: "0.5rem",
|
|
717
|
+
color: isDark ? "#F9FAFB" : "#111827",
|
|
718
|
+
boxShadow: isDark ? "0 4px 6px -1px rgba(0, 0, 0, 0.3)" : "0 4px 6px -1px rgba(0, 0, 0, 0.1)"
|
|
719
|
+
},
|
|
720
|
+
labelStyle: {
|
|
721
|
+
color: isDark ? "#F9FAFB" : "#111827",
|
|
722
|
+
fontWeight: "500",
|
|
723
|
+
marginBottom: "4px"
|
|
736
724
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
725
|
+
}
|
|
726
|
+
),
|
|
727
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
728
|
+
recharts.Bar,
|
|
729
|
+
{
|
|
730
|
+
dataKey: yAxisDataKey,
|
|
731
|
+
fill: lineColor,
|
|
732
|
+
radius: [4, 4, 0, 0],
|
|
733
|
+
maxBarSize: 60
|
|
734
|
+
}
|
|
735
|
+
)
|
|
736
|
+
] }) }) });
|
|
740
737
|
}
|
|
741
738
|
return /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { aspect: 16 / 9, children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.LineChart, { data, margin: { left: 20 }, children: [
|
|
742
739
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -975,23 +972,23 @@ const PieChart = ({ data, dataKey }) => {
|
|
|
975
972
|
)
|
|
976
973
|
] }) });
|
|
977
974
|
};
|
|
978
|
-
const columnHelper$
|
|
979
|
-
const columns$
|
|
980
|
-
columnHelper$
|
|
975
|
+
const columnHelper$3 = ui.createDataTableColumnHelper();
|
|
976
|
+
const columns$2 = [
|
|
977
|
+
columnHelper$3.accessor("sku", {
|
|
981
978
|
header: "SKU",
|
|
982
979
|
enableSorting: true,
|
|
983
980
|
sortLabel: "SKU",
|
|
984
981
|
sortAscLabel: "A-Z",
|
|
985
982
|
sortDescLabel: "Z-A"
|
|
986
983
|
}),
|
|
987
|
-
columnHelper$
|
|
984
|
+
columnHelper$3.accessor("variantName", {
|
|
988
985
|
header: "Variant Name",
|
|
989
986
|
enableSorting: true,
|
|
990
987
|
sortLabel: "Variant Name",
|
|
991
988
|
sortAscLabel: "A-Z",
|
|
992
989
|
sortDescLabel: "Z-A"
|
|
993
990
|
}),
|
|
994
|
-
columnHelper$
|
|
991
|
+
columnHelper$3.accessor("inventoryQuantity", {
|
|
995
992
|
header: "Inventory",
|
|
996
993
|
enableSorting: true,
|
|
997
994
|
sortLabel: "Inventory",
|
|
@@ -1003,10 +1000,10 @@ const columns$1 = [
|
|
|
1003
1000
|
}
|
|
1004
1001
|
})
|
|
1005
1002
|
];
|
|
1006
|
-
const PAGE_SIZE = 10;
|
|
1003
|
+
const PAGE_SIZE$1 = 10;
|
|
1007
1004
|
const ProductsTable = ({ products }) => {
|
|
1008
1005
|
const [pagination, setPagination] = React__namespace.useState({
|
|
1009
|
-
pageSize: PAGE_SIZE,
|
|
1006
|
+
pageSize: PAGE_SIZE$1,
|
|
1010
1007
|
pageIndex: 0
|
|
1011
1008
|
});
|
|
1012
1009
|
const [search, setSearch] = React__namespace.useState("");
|
|
@@ -1037,7 +1034,7 @@ const ProductsTable = ({ products }) => {
|
|
|
1037
1034
|
);
|
|
1038
1035
|
}, [products, search, sorting, pagination]);
|
|
1039
1036
|
const table = ui.useDataTable({
|
|
1040
|
-
columns: columns$
|
|
1037
|
+
columns: columns$2,
|
|
1041
1038
|
data: shownProducts,
|
|
1042
1039
|
getRowId: (product) => product.sku,
|
|
1043
1040
|
rowCount: products.length,
|
|
@@ -1072,10 +1069,10 @@ const ProductsTable = ({ products }) => {
|
|
|
1072
1069
|
}
|
|
1073
1070
|
}
|
|
1074
1071
|
),
|
|
1075
|
-
products.length > PAGE_SIZE && /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Pagination, {})
|
|
1072
|
+
products.length > PAGE_SIZE$1 && /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Pagination, {})
|
|
1076
1073
|
] });
|
|
1077
1074
|
};
|
|
1078
|
-
const BACKEND_URL$
|
|
1075
|
+
const BACKEND_URL$2 = __BACKEND_URL__ === "/" ? "" : __BACKEND_URL__;
|
|
1079
1076
|
async function retrieveProductAnalytics(date) {
|
|
1080
1077
|
if (!date || !date.from || !(date == null ? void 0 : date.to)) {
|
|
1081
1078
|
return void 0;
|
|
@@ -1083,7 +1080,7 @@ async function retrieveProductAnalytics(date) {
|
|
|
1083
1080
|
const dateFrom = dateFns.format(date.from, "yyyy-MM-dd");
|
|
1084
1081
|
const dateTo = dateFns.format(date.to, "yyyy-MM-dd");
|
|
1085
1082
|
const data = await fetch(
|
|
1086
|
-
`${BACKEND_URL$
|
|
1083
|
+
`${BACKEND_URL$2}/admin/agilo-analytics/products?date_from=${dateFrom}&date_to=${dateTo}`
|
|
1087
1084
|
);
|
|
1088
1085
|
const productAnalytics = await data.json();
|
|
1089
1086
|
return productAnalytics;
|
|
@@ -1098,11 +1095,11 @@ const useProductAnalytics = (query, options) => {
|
|
|
1098
1095
|
...options
|
|
1099
1096
|
});
|
|
1100
1097
|
};
|
|
1101
|
-
const BACKEND_URL =
|
|
1098
|
+
const BACKEND_URL$1 = __BACKEND_URL__ === "/" ? "" : __BACKEND_URL__;
|
|
1102
1099
|
async function retrieveOrderAnalytics(preset, date) {
|
|
1103
1100
|
if (!date || !date.from || !(date == null ? void 0 : date.to)) {
|
|
1104
1101
|
const data2 = await fetch(
|
|
1105
|
-
`${BACKEND_URL}/admin/agilo-analytics/orders?preset=${preset}`
|
|
1102
|
+
`${BACKEND_URL$1}/admin/agilo-analytics/orders?preset=${preset}`
|
|
1106
1103
|
);
|
|
1107
1104
|
const orderAnalytics2 = await data2.json();
|
|
1108
1105
|
return orderAnalytics2;
|
|
@@ -1110,7 +1107,7 @@ async function retrieveOrderAnalytics(preset, date) {
|
|
|
1110
1107
|
const dateFrom = dateFns.format(date.from, "yyyy-MM-dd");
|
|
1111
1108
|
const dateTo = dateFns.format(date.to, "yyyy-MM-dd");
|
|
1112
1109
|
const data = await fetch(
|
|
1113
|
-
`${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}`
|
|
1114
1111
|
);
|
|
1115
1112
|
const orderAnalytics = await data.json();
|
|
1116
1113
|
return orderAnalytics;
|
|
@@ -1151,7 +1148,7 @@ const BarChartSkeleton = () => {
|
|
|
1151
1148
|
const PieChartSkeleton = () => {
|
|
1152
1149
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full aspect-square max-h-[400px]", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-full" }) });
|
|
1153
1150
|
};
|
|
1154
|
-
const dummyData = [
|
|
1151
|
+
const dummyData$1 = [
|
|
1155
1152
|
{
|
|
1156
1153
|
a: "a",
|
|
1157
1154
|
b: "b",
|
|
@@ -1183,27 +1180,209 @@ const dummyData = [
|
|
|
1183
1180
|
c: 0
|
|
1184
1181
|
}
|
|
1185
1182
|
];
|
|
1186
|
-
const columnHelper = ui.createDataTableColumnHelper();
|
|
1187
|
-
const columns = [
|
|
1188
|
-
columnHelper.accessor("a", {
|
|
1183
|
+
const columnHelper$2 = ui.createDataTableColumnHelper();
|
|
1184
|
+
const columns$1 = [
|
|
1185
|
+
columnHelper$2.accessor("a", {
|
|
1189
1186
|
header: () => null,
|
|
1190
1187
|
cell: () => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-5" })
|
|
1191
1188
|
}),
|
|
1192
|
-
columnHelper.accessor("b", {
|
|
1189
|
+
columnHelper$2.accessor("b", {
|
|
1193
1190
|
header: () => null,
|
|
1194
1191
|
cell: () => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-5" })
|
|
1195
1192
|
}),
|
|
1196
|
-
columnHelper.accessor("c", {
|
|
1193
|
+
columnHelper$2.accessor("c", {
|
|
1197
1194
|
header: () => null,
|
|
1198
1195
|
cell: () => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "w-full h-5" })
|
|
1199
1196
|
})
|
|
1200
1197
|
];
|
|
1201
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 = () => {
|
|
1202
1381
|
const [search, setSearch] = React__namespace.useState("");
|
|
1203
1382
|
const table = ui.useDataTable({
|
|
1204
1383
|
columns,
|
|
1205
1384
|
data: dummyData,
|
|
1206
|
-
getRowId: (
|
|
1385
|
+
getRowId: (customer) => customer.a,
|
|
1207
1386
|
rowCount: dummyData.length,
|
|
1208
1387
|
search: {
|
|
1209
1388
|
state: search,
|
|
@@ -1215,6 +1394,140 @@ const ProductsTableSkeleton = () => {
|
|
|
1215
1394
|
/* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Table, {})
|
|
1216
1395
|
] });
|
|
1217
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
|
+
};
|
|
1218
1531
|
function dateToCalendarDate(date) {
|
|
1219
1532
|
return new $35ea8db9cb2ccb90$export$99faa760c7908e4f(
|
|
1220
1533
|
date.getFullYear(),
|
|
@@ -1242,16 +1555,40 @@ function rangeValueToDateRange(rangeValue) {
|
|
|
1242
1555
|
to: rangeValue.end ? calendarDateToDate(rangeValue.end) : void 0
|
|
1243
1556
|
};
|
|
1244
1557
|
}
|
|
1558
|
+
function presetToDateRange(preset) {
|
|
1559
|
+
const today = /* @__PURE__ */ new Date();
|
|
1560
|
+
if (preset === "this-month") return { from: dateFns.startOfMonth(today), to: today };
|
|
1561
|
+
if (preset === "last-month")
|
|
1562
|
+
return {
|
|
1563
|
+
from: dateFns.startOfMonth(dateFns.subMonths(today, 1)),
|
|
1564
|
+
to: dateFns.endOfMonth(dateFns.subMonths(today, 1))
|
|
1565
|
+
};
|
|
1566
|
+
return {
|
|
1567
|
+
from: dateFns.startOfMonth(dateFns.subMonths(today, 3)),
|
|
1568
|
+
to: dateFns.endOfMonth(dateFns.subMonths(today, 1))
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
const DATE_RANGE_REGEX = /^(\d{4}-\d{2}-\d{2})-(\d{4}-\d{2}-\d{2})$/;
|
|
1245
1572
|
const AnalyticsPage = () => {
|
|
1246
1573
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
1247
|
-
const [
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1574
|
+
const [searchParams, setSearchParams] = reactRouterDom.useSearchParams();
|
|
1575
|
+
const rangeParam = searchParams.get("range") || "this-month";
|
|
1576
|
+
const date = React__namespace.useMemo(() => {
|
|
1577
|
+
if (rangeParam === "this-month" || rangeParam === "last-month" || rangeParam === "last-3-months") {
|
|
1578
|
+
return presetToDateRange(rangeParam);
|
|
1579
|
+
}
|
|
1580
|
+
const dates = rangeParam.match(DATE_RANGE_REGEX);
|
|
1581
|
+
if (dates) {
|
|
1582
|
+
const from = dateFns.parse(dates[1], "yyyy-MM-dd", /* @__PURE__ */ new Date());
|
|
1583
|
+
const to = dateFns.parse(dates[2], "yyyy-MM-dd", /* @__PURE__ */ new Date());
|
|
1584
|
+
return { from, to };
|
|
1585
|
+
}
|
|
1586
|
+
return void 0;
|
|
1587
|
+
}, [rangeParam]);
|
|
1252
1588
|
const { data: products, isLoading: isLoadingProducts } = useProductAnalytics(date);
|
|
1589
|
+
const { data: customers, isLoading: isLoadingCustomers } = useCustomerAnalytics(date);
|
|
1253
1590
|
const { data: orders, isLoading: isLoadingOrders } = useOrderAnalytics(
|
|
1254
|
-
|
|
1591
|
+
["this-month", "last-month", "last-3-months"].includes(rangeParam) ? rangeParam : "custom",
|
|
1255
1592
|
date
|
|
1256
1593
|
);
|
|
1257
1594
|
const someOrderCountsGreaterThanZero = (_a = orders == null ? void 0 : orders.order_count) == null ? void 0 : _a.some(
|
|
@@ -1261,45 +1598,59 @@ const AnalyticsPage = () => {
|
|
|
1261
1598
|
(item) => item.sales > 0
|
|
1262
1599
|
);
|
|
1263
1600
|
const someTopSellingProductsGreaterThanZero = (_c = products == null ? void 0 : products.variantQuantitySold) == null ? void 0 : _c.some((item) => item.quantity > 0);
|
|
1264
|
-
const updateDatePreset = React__namespace.useCallback(
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1601
|
+
const updateDatePreset = React__namespace.useCallback(
|
|
1602
|
+
(preset) => {
|
|
1603
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
1604
|
+
switch (preset) {
|
|
1605
|
+
case "this-month":
|
|
1606
|
+
params.set("range", "this-month");
|
|
1607
|
+
break;
|
|
1608
|
+
case "last-month":
|
|
1609
|
+
params.set("range", "last-month");
|
|
1610
|
+
break;
|
|
1611
|
+
case "last-3-months":
|
|
1612
|
+
params.set("range", "last-3-months");
|
|
1613
|
+
break;
|
|
1614
|
+
case "custom":
|
|
1615
|
+
default:
|
|
1616
|
+
if (rangeParam === "this-month" || rangeParam === "last-month" || rangeParam === "last-3-months") {
|
|
1617
|
+
const currentDate = presetToDateRange(rangeParam);
|
|
1618
|
+
params.set(
|
|
1619
|
+
"range",
|
|
1620
|
+
`${dateFns.format(currentDate.from || /* @__PURE__ */ new Date(), "yyyy-MM-dd")}-${dateFns.format(
|
|
1621
|
+
currentDate.to || /* @__PURE__ */ new Date(),
|
|
1622
|
+
"yyyy-MM-dd"
|
|
1623
|
+
)}`
|
|
1624
|
+
);
|
|
1625
|
+
}
|
|
1626
|
+
break;
|
|
1627
|
+
}
|
|
1628
|
+
setSearchParams(params);
|
|
1629
|
+
},
|
|
1630
|
+
[searchParams, rangeParam, setSearchParams]
|
|
1631
|
+
);
|
|
1632
|
+
const updateUrlParams = React__namespace.useCallback(
|
|
1633
|
+
(value) => {
|
|
1634
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
1635
|
+
if ((value == null ? void 0 : value.from) && (value == null ? void 0 : value.to)) {
|
|
1636
|
+
params.set(
|
|
1637
|
+
"range",
|
|
1638
|
+
`${dateFns.format(value.from, "yyyy-MM-dd")}-${dateFns.format(
|
|
1639
|
+
value.to,
|
|
1640
|
+
"yyyy-MM-dd"
|
|
1641
|
+
)}`
|
|
1642
|
+
);
|
|
1643
|
+
}
|
|
1644
|
+
setSearchParams(params);
|
|
1645
|
+
},
|
|
1646
|
+
[searchParams, setSearchParams]
|
|
1647
|
+
);
|
|
1294
1648
|
const handleDateRangeChange = React__namespace.useCallback(
|
|
1295
1649
|
(value) => {
|
|
1296
1650
|
const newDateRange = rangeValueToDateRange(value);
|
|
1297
|
-
|
|
1298
|
-
if (selectValue !== "custom") {
|
|
1299
|
-
setSelectValue("custom");
|
|
1300
|
-
}
|
|
1651
|
+
updateUrlParams(newDateRange);
|
|
1301
1652
|
},
|
|
1302
|
-
[]
|
|
1653
|
+
[updateUrlParams]
|
|
1303
1654
|
);
|
|
1304
1655
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
|
|
1305
1656
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-x-2 gap-y-4 items-center justify-between px-6 py-4", children: [
|
|
@@ -1310,7 +1661,9 @@ const AnalyticsPage = () => {
|
|
|
1310
1661
|
{
|
|
1311
1662
|
disabled: isLoadingOrders || isLoadingProducts,
|
|
1312
1663
|
defaultValue: "this-month",
|
|
1313
|
-
value:
|
|
1664
|
+
value: ["this-month", "last-month", "last-3-months"].includes(
|
|
1665
|
+
rangeParam
|
|
1666
|
+
) ? rangeParam : "custom",
|
|
1314
1667
|
onValueChange: updateDatePreset,
|
|
1315
1668
|
children: [
|
|
1316
1669
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, {}) }),
|
|
@@ -1406,193 +1759,306 @@ const AnalyticsPage = () => {
|
|
|
1406
1759
|
)
|
|
1407
1760
|
] })
|
|
1408
1761
|
] }),
|
|
1409
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1762
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1763
|
+
ui.Tabs,
|
|
1764
|
+
{
|
|
1765
|
+
value: searchParams.get("tab") || "orders",
|
|
1766
|
+
onValueChange: (value) => {
|
|
1767
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
1768
|
+
params.set("tab", value);
|
|
1769
|
+
setSearchParams(params);
|
|
1770
|
+
},
|
|
1771
|
+
children: [
|
|
1772
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.List, { children: [
|
|
1773
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1774
|
+
ui.Tabs.Trigger,
|
|
1775
|
+
{
|
|
1776
|
+
value: "orders",
|
|
1777
|
+
disabled: isLoadingOrders || isLoadingProducts,
|
|
1778
|
+
children: "Orders"
|
|
1779
|
+
}
|
|
1780
|
+
),
|
|
1781
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1782
|
+
ui.Tabs.Trigger,
|
|
1783
|
+
{
|
|
1784
|
+
value: "products",
|
|
1785
|
+
disabled: isLoadingOrders || isLoadingProducts,
|
|
1786
|
+
children: "Products"
|
|
1787
|
+
}
|
|
1788
|
+
),
|
|
1789
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1790
|
+
ui.Tabs.Trigger,
|
|
1791
|
+
{
|
|
1792
|
+
value: "customers",
|
|
1793
|
+
disabled: isLoadingOrders || isLoadingProducts,
|
|
1794
|
+
children: "Customers"
|
|
1795
|
+
}
|
|
1796
|
+
)
|
|
1797
|
+
] }),
|
|
1798
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-8", children: [
|
|
1799
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.Content, { value: "orders", children: [
|
|
1800
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-md:flex-col gap-4 mb-4", children: [
|
|
1801
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 flex-1", children: [
|
|
1802
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "relative", children: [
|
|
1803
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.ShoppingCart, { className: "absolute right-6 top-4 text-ui-fg-muted" }),
|
|
1804
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: "Total Orders" }),
|
|
1805
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(SmallCardSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1806
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: (orders == null ? void 0 : orders.total_orders) || 0 }),
|
|
1807
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
1808
|
+
((orders == null ? void 0 : orders.prev_orders_percent) || 0) > 0 && "+",
|
|
1809
|
+
(orders == null ? void 0 : orders.prev_orders_percent) || 0,
|
|
1810
|
+
"% from previous period"
|
|
1811
|
+
] })
|
|
1812
|
+
] })
|
|
1813
|
+
] }),
|
|
1814
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1815
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Orders Over Time" }),
|
|
1816
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Total number of orders in the selected period" }),
|
|
1817
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(LineChartSkeleton, {}) : (orders == null ? void 0 : orders.order_count) && ((_d = orders == null ? void 0 : orders.order_count) == null ? void 0 : _d.length) > 0 && someOrderCountsGreaterThanZero ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1818
|
+
LineChart,
|
|
1819
|
+
{
|
|
1820
|
+
data: orders == null ? void 0 : orders.order_count,
|
|
1821
|
+
xAxisDataKey: "name",
|
|
1822
|
+
yAxisDataKey: "count"
|
|
1823
|
+
}
|
|
1824
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1825
|
+
ui.Text,
|
|
1826
|
+
{
|
|
1827
|
+
size: "small",
|
|
1828
|
+
className: "text-ui-fg-muted text-center",
|
|
1829
|
+
children: "No data available for the selected period."
|
|
1830
|
+
}
|
|
1831
|
+
)
|
|
1832
|
+
] })
|
|
1833
|
+
] }),
|
|
1834
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 flex-1", children: [
|
|
1835
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "relative", children: [
|
|
1836
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChartNoAxesCombined, { className: "absolute right-6 text-ui-fg-muted top-4 size-[15px]" }),
|
|
1837
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: "Total Sales" }),
|
|
1838
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(SmallCardSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1839
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: new Intl.NumberFormat("en-US", {
|
|
1840
|
+
style: "currency",
|
|
1841
|
+
currency: (orders == null ? void 0 : orders.currency_code) || "EUR"
|
|
1842
|
+
}).format((orders == null ? void 0 : orders.total_sales) || 0) }),
|
|
1843
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
1844
|
+
((orders == null ? void 0 : orders.prev_sales_percent) || 0) > 0 && "+",
|
|
1845
|
+
(orders == null ? void 0 : orders.prev_sales_percent) || 0,
|
|
1846
|
+
"% from previous period"
|
|
1847
|
+
] })
|
|
1848
|
+
] })
|
|
1849
|
+
] }),
|
|
1850
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1851
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Sales Over Time" }),
|
|
1852
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: [
|
|
1853
|
+
"Total sales in the selected period (",
|
|
1854
|
+
orders == null ? void 0 : orders.currency_code,
|
|
1855
|
+
")"
|
|
1856
|
+
] }),
|
|
1857
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(LineChartSkeleton, {}) : (orders == null ? void 0 : orders.order_sales) && ((_e = orders == null ? void 0 : orders.order_sales) == null ? void 0 : _e.length) > 0 && someOrderSalesGreaterThanZero ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1858
|
+
LineChart,
|
|
1859
|
+
{
|
|
1860
|
+
data: orders.order_sales,
|
|
1861
|
+
xAxisDataKey: "name",
|
|
1862
|
+
yAxisDataKey: "sales",
|
|
1863
|
+
lineColor: "#82ca9d",
|
|
1864
|
+
yAxisTickFormatter: (value) => new Intl.NumberFormat("en-US", {
|
|
1865
|
+
currency: orders.currency_code,
|
|
1866
|
+
maximumFractionDigits: 0
|
|
1867
|
+
}).format(value)
|
|
1868
|
+
}
|
|
1869
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1870
|
+
ui.Text,
|
|
1871
|
+
{
|
|
1872
|
+
size: "small",
|
|
1873
|
+
className: "text-ui-fg-muted text-center",
|
|
1874
|
+
children: "No data available for the selected period."
|
|
1875
|
+
}
|
|
1876
|
+
)
|
|
1441
1877
|
] })
|
|
1442
1878
|
] })
|
|
1443
1879
|
] }),
|
|
1444
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1445
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1880
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-md:flex-col gap-4", children: [
|
|
1881
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1882
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Top Regions by Sales" }),
|
|
1883
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Sales breakdown by region in the selected period" }),
|
|
1884
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(BarChartSkeleton, {}) : (orders == null ? void 0 : orders.regions) && ((_f = orders == null ? void 0 : orders.regions) == null ? void 0 : _f.length) > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1885
|
+
BarChart,
|
|
1886
|
+
{
|
|
1887
|
+
data: orders.regions,
|
|
1888
|
+
xAxisDataKey: "name",
|
|
1889
|
+
yAxisDataKey: "sales",
|
|
1890
|
+
lineColor: "#82ca9d",
|
|
1891
|
+
useStableColors: true,
|
|
1892
|
+
colorKeyField: "name",
|
|
1893
|
+
yAxisTickFormatter: (value) => new Intl.NumberFormat("en-US", {
|
|
1894
|
+
currency: orders.currency_code,
|
|
1895
|
+
maximumFractionDigits: 0
|
|
1896
|
+
}).format(value)
|
|
1897
|
+
}
|
|
1898
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1899
|
+
ui.Text,
|
|
1900
|
+
{
|
|
1901
|
+
size: "small",
|
|
1902
|
+
className: "text-ui-fg-muted text-center",
|
|
1903
|
+
children: "No data available for the selected period."
|
|
1904
|
+
}
|
|
1905
|
+
)
|
|
1906
|
+
] }) }),
|
|
1907
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1908
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Order Status Breakdown" }),
|
|
1909
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Distribution of orders by status in the selected period" }),
|
|
1910
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(PieChartSkeleton, {}) : (orders == null ? void 0 : orders.statuses) && ((_g = orders == null ? void 0 : orders.statuses) == null ? void 0 : _g.length) > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(PieChart, { data: orders == null ? void 0 : orders.statuses, dataKey: "count" }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1911
|
+
ui.Text,
|
|
1912
|
+
{
|
|
1913
|
+
size: "small",
|
|
1914
|
+
className: "text-ui-fg-muted text-center",
|
|
1915
|
+
children: "No data available for the selected period."
|
|
1916
|
+
}
|
|
1917
|
+
)
|
|
1918
|
+
] }) })
|
|
1919
|
+
] })
|
|
1920
|
+
] }),
|
|
1921
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.Content, { value: "products", children: [
|
|
1922
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "mb-4 min-h-[9.375rem]", children: [
|
|
1923
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Top-Selling Products" }),
|
|
1924
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products by quantity sold in selected period" }),
|
|
1925
|
+
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(BarChartSkeleton, {}) : (products == null ? void 0 : products.variantQuantitySold) && someTopSellingProductsGreaterThanZero ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1926
|
+
BarChart,
|
|
1456
1927
|
{
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1928
|
+
data: products.variantQuantitySold,
|
|
1929
|
+
xAxisDataKey: "title",
|
|
1930
|
+
yAxisDataKey: "quantity",
|
|
1931
|
+
lineColor: "#82ca9d",
|
|
1932
|
+
useStableColors: true,
|
|
1933
|
+
colorKeyField: "title"
|
|
1460
1934
|
}
|
|
1461
|
-
)
|
|
1935
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted text-center", children: "No data available for the selected period." })
|
|
1936
|
+
] }),
|
|
1937
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4 max-xl:flex-col", children: [
|
|
1938
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { children: [
|
|
1939
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Out-of-Stock Variants" }),
|
|
1940
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products with zero inventory" }),
|
|
1941
|
+
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(ProductsTableSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1942
|
+
ProductsTable,
|
|
1943
|
+
{
|
|
1944
|
+
products: ((_h = products == null ? void 0 : products.lowStockVariants) == null ? void 0 : _h.filter(
|
|
1945
|
+
(product) => product.inventoryQuantity === 0
|
|
1946
|
+
)) || []
|
|
1947
|
+
}
|
|
1948
|
+
)
|
|
1949
|
+
] }),
|
|
1950
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { children: [
|
|
1951
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Low Stock Variants" }),
|
|
1952
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products with inventory below threshold" }),
|
|
1953
|
+
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(ProductsTableSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1954
|
+
ProductsTable,
|
|
1955
|
+
{
|
|
1956
|
+
products: ((_i = products == null ? void 0 : products.lowStockVariants) == null ? void 0 : _i.filter(
|
|
1957
|
+
(product) => product.inventoryQuantity > 0
|
|
1958
|
+
)) || []
|
|
1959
|
+
}
|
|
1960
|
+
)
|
|
1961
|
+
] })
|
|
1462
1962
|
] })
|
|
1463
1963
|
] }),
|
|
1464
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1465
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1466
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
(
|
|
1476
|
-
|
|
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
|
+
) }) })
|
|
1477
1993
|
] })
|
|
1478
1994
|
] })
|
|
1479
1995
|
] }),
|
|
1480
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1481
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1482
|
-
|
|
1483
|
-
"
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
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,
|
|
1501
2051
|
{
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
children: "No data available for the selected period."
|
|
2052
|
+
customers: (customers == null ? void 0 : customers.customer_sales) || [],
|
|
2053
|
+
currencyCode: (customers == null ? void 0 : customers.currency_code) || "EUR"
|
|
1505
2054
|
}
|
|
1506
2055
|
)
|
|
1507
|
-
] })
|
|
2056
|
+
] }) })
|
|
1508
2057
|
] })
|
|
1509
|
-
] }),
|
|
1510
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-md:flex-col gap-4", children: [
|
|
1511
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1512
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Top Regions by Sales" }),
|
|
1513
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Sales breakdown by region in the selected period" }),
|
|
1514
|
-
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(BarChartSkeleton, {}) : (orders == null ? void 0 : orders.regions) && ((_f = orders == null ? void 0 : orders.regions) == null ? void 0 : _f.length) > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1515
|
-
BarChart,
|
|
1516
|
-
{
|
|
1517
|
-
data: orders.regions,
|
|
1518
|
-
xAxisDataKey: "name",
|
|
1519
|
-
yAxisDataKey: "sales",
|
|
1520
|
-
lineColor: "#82ca9d",
|
|
1521
|
-
useStableColors: true,
|
|
1522
|
-
colorKeyField: "name",
|
|
1523
|
-
yAxisTickFormatter: (value) => new Intl.NumberFormat("en-US", {
|
|
1524
|
-
currency: orders.currency_code,
|
|
1525
|
-
maximumFractionDigits: 0
|
|
1526
|
-
}).format(value)
|
|
1527
|
-
}
|
|
1528
|
-
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1529
|
-
ui.Text,
|
|
1530
|
-
{
|
|
1531
|
-
size: "small",
|
|
1532
|
-
className: "text-ui-fg-muted text-center",
|
|
1533
|
-
children: "No data available for the selected period."
|
|
1534
|
-
}
|
|
1535
|
-
)
|
|
1536
|
-
] }) }),
|
|
1537
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1538
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Order Status Breakdown" }),
|
|
1539
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Distribution of orders by status in the selected period" }),
|
|
1540
|
-
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(PieChartSkeleton, {}) : (orders == null ? void 0 : orders.statuses) && ((_g = orders == null ? void 0 : orders.statuses) == null ? void 0 : _g.length) > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(PieChart, { data: orders == null ? void 0 : orders.statuses, dataKey: "count" }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1541
|
-
ui.Text,
|
|
1542
|
-
{
|
|
1543
|
-
size: "small",
|
|
1544
|
-
className: "text-ui-fg-muted text-center",
|
|
1545
|
-
children: "No data available for the selected period."
|
|
1546
|
-
}
|
|
1547
|
-
)
|
|
1548
|
-
] }) })
|
|
1549
2058
|
] })
|
|
1550
|
-
]
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Top-Selling Products" }),
|
|
1554
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products by quantity sold in selected period" }),
|
|
1555
|
-
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(BarChartSkeleton, {}) : (products == null ? void 0 : products.variantQuantitySold) && someTopSellingProductsGreaterThanZero ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1556
|
-
BarChart,
|
|
1557
|
-
{
|
|
1558
|
-
data: products.variantQuantitySold,
|
|
1559
|
-
xAxisDataKey: "title",
|
|
1560
|
-
yAxisDataKey: "quantity",
|
|
1561
|
-
lineColor: "#82ca9d",
|
|
1562
|
-
useStableColors: true,
|
|
1563
|
-
colorKeyField: "title"
|
|
1564
|
-
}
|
|
1565
|
-
) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted text-center", children: "No data available for the selected period." })
|
|
1566
|
-
] }),
|
|
1567
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4 max-xl:flex-col", children: [
|
|
1568
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { children: [
|
|
1569
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Out-of-Stock Variants" }),
|
|
1570
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products with zero inventory" }),
|
|
1571
|
-
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(ProductsTableSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1572
|
-
ProductsTable,
|
|
1573
|
-
{
|
|
1574
|
-
products: ((_h = products == null ? void 0 : products.lowStockVariants) == null ? void 0 : _h.filter(
|
|
1575
|
-
(product) => product.inventoryQuantity === 0
|
|
1576
|
-
)) || []
|
|
1577
|
-
}
|
|
1578
|
-
)
|
|
1579
|
-
] }),
|
|
1580
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { children: [
|
|
1581
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Low Stock Variants" }),
|
|
1582
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products with inventory below threshold" }),
|
|
1583
|
-
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(ProductsTableSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1584
|
-
ProductsTable,
|
|
1585
|
-
{
|
|
1586
|
-
products: ((_i = products == null ? void 0 : products.lowStockVariants) == null ? void 0 : _i.filter(
|
|
1587
|
-
(product) => product.inventoryQuantity > 0
|
|
1588
|
-
)) || []
|
|
1589
|
-
}
|
|
1590
|
-
)
|
|
1591
|
-
] })
|
|
1592
|
-
] })
|
|
1593
|
-
] })
|
|
1594
|
-
] })
|
|
1595
|
-
] }) })
|
|
2059
|
+
]
|
|
2060
|
+
}
|
|
2061
|
+
) })
|
|
1596
2062
|
] });
|
|
1597
2063
|
};
|
|
1598
2064
|
const config = adminSdk.defineRouteConfig({
|