@deenruv/dashboard-widgets-plugin 1.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.
Files changed (108) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +58 -0
  3. package/dist/plugin-server/constants.d.ts +4 -0
  4. package/dist/plugin-server/constants.js +12 -0
  5. package/dist/plugin-server/controllers/admin-ui-controller.d.ts +4 -0
  6. package/dist/plugin-server/controllers/admin-ui-controller.js +46 -0
  7. package/dist/plugin-server/controllers/refresh-view-controller.d.ts +8 -0
  8. package/dist/plugin-server/controllers/refresh-view-controller.js +41 -0
  9. package/dist/plugin-server/index.d.ts +1 -0
  10. package/dist/plugin-server/index.js +17 -0
  11. package/dist/plugin-server/materialisedViewEntities/order_summary.d.ts +9 -0
  12. package/dist/plugin-server/materialisedViewEntities/order_summary.js +79 -0
  13. package/dist/plugin-server/materialisedViewEntities/orders_summary_with_state.d.ts +10 -0
  14. package/dist/plugin-server/materialisedViewEntities/orders_summary_with_state.js +79 -0
  15. package/dist/plugin-server/materialisedViewEntities/total_products.d.ts +7 -0
  16. package/dist/plugin-server/materialisedViewEntities/total_products.js +62 -0
  17. package/dist/plugin-server/materialisedViewEntities/total_products_with_state.d.ts +9 -0
  18. package/dist/plugin-server/materialisedViewEntities/total_products_with_state.js +62 -0
  19. package/dist/plugin-server/plugin.d.ts +6 -0
  20. package/dist/plugin-server/plugin.js +149 -0
  21. package/dist/plugin-server/raw-sql.d.ts +8 -0
  22. package/dist/plugin-server/raw-sql.js +48 -0
  23. package/dist/plugin-server/resolvers/admin.resolver.d.ts +47 -0
  24. package/dist/plugin-server/resolvers/admin.resolver.js +63 -0
  25. package/dist/plugin-server/services/metrics.service.d.ts +30 -0
  26. package/dist/plugin-server/services/metrics.service.js +272 -0
  27. package/dist/plugin-server/types.d.ts +20 -0
  28. package/dist/plugin-server/types.js +2 -0
  29. package/dist/plugin-server/utils.d.ts +1 -0
  30. package/dist/plugin-server/utils.js +12 -0
  31. package/dist/plugin-server/zeus/const.d.ts +6 -0
  32. package/dist/plugin-server/zeus/const.js +3675 -0
  33. package/dist/plugin-server/zeus/index.d.ts +18709 -0
  34. package/dist/plugin-server/zeus/index.js +1122 -0
  35. package/dist/plugin-server/zeus/typedDocumentNode.d.ts +3 -0
  36. package/dist/plugin-server/zeus/typedDocumentNode.js +16 -0
  37. package/dist/plugin-ui/components/CategoriesChartWidget/dashCaseToSpaces.d.ts +1 -0
  38. package/dist/plugin-ui/components/CategoriesChartWidget/dashCaseToSpaces.js +6 -0
  39. package/dist/plugin-ui/components/CategoriesChartWidget/index.d.ts +2 -0
  40. package/dist/plugin-ui/components/CategoriesChartWidget/index.js +100 -0
  41. package/dist/plugin-ui/components/LatestOrdersWidget/index.d.ts +4 -0
  42. package/dist/plugin-ui/components/LatestOrdersWidget/index.js +96 -0
  43. package/dist/plugin-ui/components/LatestOrdersWidget/paymentMethod.d.ts +6 -0
  44. package/dist/plugin-ui/components/LatestOrdersWidget/paymentMethod.js +7 -0
  45. package/dist/plugin-ui/components/OrdersWidget/CustomTooltip.d.ts +18 -0
  46. package/dist/plugin-ui/components/OrdersWidget/CustomTooltip.js +92 -0
  47. package/dist/plugin-ui/components/OrdersWidget/GroupBySelect.d.ts +8 -0
  48. package/dist/plugin-ui/components/OrdersWidget/GroupBySelect.js +17 -0
  49. package/dist/plugin-ui/components/OrdersWidget/MetricCustomDates.d.ts +9 -0
  50. package/dist/plugin-ui/components/OrdersWidget/MetricCustomDates.js +27 -0
  51. package/dist/plugin-ui/components/OrdersWidget/MetricTypeSelect.d.ts +9 -0
  52. package/dist/plugin-ui/components/OrdersWidget/MetricTypeSelect.js +17 -0
  53. package/dist/plugin-ui/components/OrdersWidget/OrdersChart.d.ts +24 -0
  54. package/dist/plugin-ui/components/OrdersWidget/OrdersChart.js +46 -0
  55. package/dist/plugin-ui/components/OrdersWidget/OrdersSummaryTile.d.ts +13 -0
  56. package/dist/plugin-ui/components/OrdersWidget/OrdersSummaryTile.js +115 -0
  57. package/dist/plugin-ui/components/OrdersWidget/ProductSelector.d.ts +17 -0
  58. package/dist/plugin-ui/components/OrdersWidget/ProductSelector.js +37 -0
  59. package/dist/plugin-ui/components/OrdersWidget/RatioBadge.d.ts +6 -0
  60. package/dist/plugin-ui/components/OrdersWidget/RatioBadge.js +12 -0
  61. package/dist/plugin-ui/components/OrdersWidget/index.d.ts +2 -0
  62. package/dist/plugin-ui/components/OrdersWidget/index.js +229 -0
  63. package/dist/plugin-ui/components/ProductsChartWidget/CustomBarChartTooltip.d.ts +9 -0
  64. package/dist/plugin-ui/components/ProductsChartWidget/CustomBarChartTooltip.js +14 -0
  65. package/dist/plugin-ui/components/ProductsChartWidget/index.d.ts +2 -0
  66. package/dist/plugin-ui/components/ProductsChartWidget/index.js +116 -0
  67. package/dist/plugin-ui/components/index.d.ts +4 -0
  68. package/dist/plugin-ui/components/index.js +4 -0
  69. package/dist/plugin-ui/components/shared/EmptyData.d.ts +6 -0
  70. package/dist/plugin-ui/components/shared/EmptyData.js +8 -0
  71. package/dist/plugin-ui/components/shared/MetricsRangeSelect.d.ts +10 -0
  72. package/dist/plugin-ui/components/shared/MetricsRangeSelect.js +26 -0
  73. package/dist/plugin-ui/components/shared/OrderStatesSelect.d.ts +8 -0
  74. package/dist/plugin-ui/components/shared/OrderStatesSelect.js +28 -0
  75. package/dist/plugin-ui/components/shared/PeriodSelect.d.ts +20 -0
  76. package/dist/plugin-ui/components/shared/PeriodSelect.js +56 -0
  77. package/dist/plugin-ui/components/shared/colors.d.ts +1 -0
  78. package/dist/plugin-ui/components/shared/colors.js +1 -0
  79. package/dist/plugin-ui/components/shared/index.d.ts +3 -0
  80. package/dist/plugin-ui/components/shared/index.js +3 -0
  81. package/dist/plugin-ui/graphql/index.d.ts +2 -0
  82. package/dist/plugin-ui/graphql/index.js +2 -0
  83. package/dist/plugin-ui/graphql/queries.d.ts +425 -0
  84. package/dist/plugin-ui/graphql/queries.js +182 -0
  85. package/dist/plugin-ui/graphql/selectors.d.ts +19 -0
  86. package/dist/plugin-ui/graphql/selectors.js +21 -0
  87. package/dist/plugin-ui/index.d.ts +9 -0
  88. package/dist/plugin-ui/index.js +21 -0
  89. package/dist/plugin-ui/locales/en/index.d.ts +72 -0
  90. package/dist/plugin-ui/locales/en/index.js +2 -0
  91. package/dist/plugin-ui/locales/en/test.json +71 -0
  92. package/dist/plugin-ui/locales/pl/index.d.ts +71 -0
  93. package/dist/plugin-ui/locales/pl/index.js +2 -0
  94. package/dist/plugin-ui/locales/pl/test.json +70 -0
  95. package/dist/plugin-ui/tsconfig.json +18 -0
  96. package/dist/plugin-ui/types.d.ts +64 -0
  97. package/dist/plugin-ui/types.js +14 -0
  98. package/dist/plugin-ui/utils.d.ts +70 -0
  99. package/dist/plugin-ui/utils.js +366 -0
  100. package/dist/plugin-ui/widgets.d.ts +15 -0
  101. package/dist/plugin-ui/widgets.js +36 -0
  102. package/dist/plugin-ui/zeus/const.d.ts +6 -0
  103. package/dist/plugin-ui/zeus/const.js +3672 -0
  104. package/dist/plugin-ui/zeus/index.d.ts +18709 -0
  105. package/dist/plugin-ui/zeus/index.js +1114 -0
  106. package/dist/plugin-ui/zeus/typedDocumentNode.d.ts +3 -0
  107. package/dist/plugin-ui/zeus/typedDocumentNode.js +9 -0
  108. package/package.json +52 -0
@@ -0,0 +1,3 @@
1
+ import { TypedDocumentNode } from '@graphql-typed-document-node/core';
2
+ import { ValueTypes, GenericOperation, OperationOptions, GraphQLTypes, InputType, ScalarDefinition, ThunderGraphQLOptions, ExtractVariables } from './';
3
+ export declare const typedGql: <O extends "query" | "mutation", SCLR extends ScalarDefinition, R extends keyof ValueTypes = GenericOperation<O>>(operation: O, graphqlOptions?: ThunderGraphQLOptions<SCLR> | undefined) => <Z extends ValueTypes[R]>(o: Z & { [P in keyof Z]: P extends keyof ValueTypes[R] ? Z[P] : never; }, ops?: OperationOptions) => TypedDocumentNode<InputType<GraphQLTypes[R], Z, SCLR>, ExtractVariables<Z>>;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.typedGql = void 0;
7
+ const graphql_tag_1 = __importDefault(require("graphql-tag"));
8
+ const _1 = require("./");
9
+ const typedGql = (operation, graphqlOptions) => (o, ops) => {
10
+ const str = (0, _1.Zeus)(operation, o, {
11
+ operationOptions: ops,
12
+ scalars: graphqlOptions === null || graphqlOptions === void 0 ? void 0 : graphqlOptions.scalars,
13
+ });
14
+ return (0, graphql_tag_1.default)(str);
15
+ };
16
+ exports.typedGql = typedGql;
@@ -0,0 +1 @@
1
+ export declare function dashCaseToSpaces(input: string | undefined): string;
@@ -0,0 +1,6 @@
1
+ export function dashCaseToSpaces(input) {
2
+ if (!input)
3
+ return "";
4
+ const spaced = input.replace(/-/g, " ");
5
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();
6
+ }
@@ -0,0 +1,2 @@
1
+ import React from "react";
2
+ export declare const CategoriesChartWidget: () => React.JSX.Element;
@@ -0,0 +1,100 @@
1
+ import React from "react";
2
+ import { Cell, Pie, PieChart } from "recharts";
3
+ import { Card, CardContent, CardHeader, CardTitle, ChartContainer, ChartTooltip, ChartTooltipContent, Separator, useLazyQuery, useSettings, useTranslation, } from "@deenruv/react-ui-devkit";
4
+ import { useCallback, useEffect, useState } from "react";
5
+ import { ChartMetricType, MetricIntervalType } from "../../zeus";
6
+ import { endOfToday, startOfToday } from "date-fns";
7
+ import { PeriodSelect, Periods } from "../shared";
8
+ import { dashCaseToSpaces } from "./dashCaseToSpaces";
9
+ import { colors, EmptyData } from "../shared";
10
+ import { CategoriesMetricQuery, ProductCollectionsQuery } from "../../graphql";
11
+ export const CategoriesChartWidget = () => {
12
+ const { t } = useTranslation("dashboard-widgets-plugin");
13
+ const [chartData, setChartData] = useState([]);
14
+ const channel = useSettings((state) => state.selectedChannel);
15
+ const [fetchBetterMetrics] = useLazyQuery(CategoriesMetricQuery);
16
+ const [fetchProductCollections] = useLazyQuery(ProductCollectionsQuery);
17
+ const [selectedPeriod, setSelectedPeriod] = useState({
18
+ period: Periods.Today,
19
+ text: t("today"),
20
+ start: startOfToday(),
21
+ end: endOfToday(),
22
+ });
23
+ const fetchData = useCallback(async () => {
24
+ fetchBetterMetrics({
25
+ input: {
26
+ orderStates: [],
27
+ interval: MetricIntervalType.Day,
28
+ range: {
29
+ start: selectedPeriod.start,
30
+ end: selectedPeriod.end,
31
+ },
32
+ types: [ChartMetricType.OrderTotalProductsCount],
33
+ },
34
+ }).then(({ chartMetric }) => {
35
+ const entries = chartMetric.data[0].entries;
36
+ const salesTotals = {};
37
+ entries.forEach((entry) => {
38
+ entry.additionalData?.forEach((product) => {
39
+ if (salesTotals[product.id]) {
40
+ salesTotals[product.id].quantity += product.quantity;
41
+ }
42
+ else {
43
+ salesTotals[product.id] = {
44
+ name: product.name,
45
+ quantity: product.quantity,
46
+ };
47
+ }
48
+ });
49
+ });
50
+ fetchProductCollections({ in: Object.keys(salesTotals) }).then(({ products }) => {
51
+ const categoryCounts = {};
52
+ products?.items.forEach(({ collections }) => {
53
+ collections
54
+ .filter((c) => c.slug !== "wszystkie")
55
+ .forEach((category) => {
56
+ const categoryName = dashCaseToSpaces(category.slug.trim());
57
+ if (categoryCounts[categoryName]) {
58
+ categoryCounts[categoryName] += 1;
59
+ }
60
+ else {
61
+ categoryCounts[categoryName] = 1;
62
+ }
63
+ });
64
+ });
65
+ const _chartData = Object.entries(categoryCounts)
66
+ .map(([category, count]) => ({
67
+ category,
68
+ value: count,
69
+ }))
70
+ .sort((a, b) => b.value - a.value)
71
+ .slice(0, 5);
72
+ setChartData(_chartData);
73
+ });
74
+ });
75
+ }, [selectedPeriod]);
76
+ useEffect(() => {
77
+ fetchData();
78
+ }, [channel, selectedPeriod]);
79
+ const chartConfig = chartData.reduce((config, item, index) => {
80
+ config[item.category] = {
81
+ label: item.category,
82
+ color: colors[index],
83
+ };
84
+ return config;
85
+ }, {});
86
+ const handlePeriodChange = useCallback((periodData) => {
87
+ setSelectedPeriod(periodData);
88
+ }, []);
89
+ return (React.createElement(Card, { className: "flex h-full flex-col border-0 shadow-none" },
90
+ React.createElement(CardHeader, { className: "flex justify-between" },
91
+ React.createElement("div", { className: "-mb-px flex items-center gap-8" },
92
+ React.createElement(CardTitle, { className: "text-lg" }, t("categories")),
93
+ React.createElement(PeriodSelect, { selectedPeriod: selectedPeriod.period, onPeriodChange: handlePeriodChange }))),
94
+ React.createElement(Separator, { className: "mb-3" }),
95
+ React.createElement(CardContent, { className: "flex flex-1 items-center justify-center pb-0" }, !chartData.length ? (React.createElement("div", { className: "flex flex-col items-center text-center" },
96
+ React.createElement(EmptyData, { text: t("emptyData") }))) : (React.createElement(ChartContainer, { config: chartConfig, className: "[&_.recharts-pie-label-text]:fill-foreground mx-auto aspect-square max-h-[400px] pb-0", style: { height: `300px`, width: "100%" } },
97
+ React.createElement(PieChart, null,
98
+ React.createElement(ChartTooltip, { content: React.createElement(ChartTooltipContent, { hideLabel: true }) }),
99
+ React.createElement(Pie, { data: chartData, dataKey: "value", label: true, nameKey: "category" }, chartData.map((entry, index) => (React.createElement(Cell, { key: `cell-${index}`, fill: chartConfig[entry.category].color }))))))))));
100
+ };
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ type LatestOrdersProps = object;
3
+ export declare const LatestOrdersWidget: React.FC<LatestOrdersProps>;
4
+ export {};
@@ -0,0 +1,96 @@
1
+ import { Badge, Button, Card, CardContent, CardHeader, CardTitle, EmptyState, PaymentMethodImage, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tooltip, TooltipContent, TooltipTrigger, Separator, OrderStateBadge, useQuery, useTranslation, Routes, priceFormatter, useWidgetsStore, useSettings, TableLabel, } from "@deenruv/react-ui-devkit";
2
+ import { LatestOrdersQuery } from "../../graphql";
3
+ import { flexRender, getCoreRowModel, useReactTable, } from "@tanstack/react-table";
4
+ import { formatDistanceToNow } from "date-fns";
5
+ import { pl } from "date-fns/locale/pl";
6
+ import { ArrowRight, Hash, RefreshCw } from "lucide-react";
7
+ import React, { useEffect, useState } from "react";
8
+ import { NavLink, useNavigate } from "react-router-dom";
9
+ export const LatestOrdersWidget = () => {
10
+ const { t } = useTranslation("dashboard-widgets-plugin");
11
+ const navigate = useNavigate();
12
+ const channel = useSettings((state) => state.selectedChannel);
13
+ const [isLoading, setIsLoading] = useState(false);
14
+ const language = useWidgetsStore((p) => p.context?.language);
15
+ const { data: latestOrdersData, runQuery: getOrders } = useQuery(LatestOrdersQuery);
16
+ const orders = latestOrdersData?.orders?.items || [];
17
+ useEffect(() => {
18
+ setIsLoading(true);
19
+ getOrders({
20
+ input: { channelId: channel?.id, first: 5, after: null },
21
+ }).finally(() => {
22
+ setIsLoading(false);
23
+ });
24
+ }, [channel]);
25
+ const columns = [
26
+ {
27
+ accessorKey: "id",
28
+ header: () => React.createElement(TableLabel, null, t("orders:table.id")),
29
+ cell: ({ row }) => React.createElement("span", null, row.original.id),
30
+ },
31
+ {
32
+ accessorKey: "payments",
33
+ header: () => React.createElement(TableLabel, null, t("dashboard:payment")),
34
+ cell: ({ row }) => {
35
+ const type = row.original.payments?.[0]?.method;
36
+ if (!type)
37
+ return React.createElement(React.Fragment, null);
38
+ return React.createElement(PaymentMethodImage, { paymentType: type });
39
+ },
40
+ },
41
+ {
42
+ accessorKey: "code",
43
+ header: () => React.createElement(TableLabel, null, t("orders:table.code")),
44
+ cell: ({ row }) => (React.createElement(Tooltip, null,
45
+ React.createElement(TooltipTrigger, null,
46
+ React.createElement(Badge, { variant: "outline", className: "flex w-full items-center justify-center", onClick: () => navigate(Routes.orders.to(row.original.id)) },
47
+ React.createElement(Hash, { size: 16 }),
48
+ React.createElement(ArrowRight, { className: "pl-1", size: 16 }))),
49
+ React.createElement(TooltipContent, null, row.original.code))),
50
+ },
51
+ {
52
+ accessorKey: "state",
53
+ header: () => React.createElement(TableLabel, null, t("orders:table.state")),
54
+ cell: ({ row }) => React.createElement(OrderStateBadge, { state: row.original.state }),
55
+ },
56
+ {
57
+ accessorKey: "totalWithTax",
58
+ header: () => React.createElement(TableLabel, null, t("orders:table.totalWithTax")),
59
+ cell: ({ row }) => (React.createElement("span", null, priceFormatter(row.original.totalWithTax, row.original.currencyCode))),
60
+ },
61
+ {
62
+ accessorKey: "createdAt",
63
+ header: () => React.createElement(TableLabel, null, t("orders:table.createdAt")),
64
+ cell: ({ row }) => (React.createElement("span", null, formatDistanceToNow(new Date(row.original.createdAt), {
65
+ locale: language === "pl" ? pl : undefined,
66
+ addSuffix: true,
67
+ }))),
68
+ },
69
+ ];
70
+ const table = useReactTable({
71
+ data: orders || [],
72
+ columns,
73
+ getCoreRowModel: getCoreRowModel(),
74
+ });
75
+ return (React.createElement(Card, null,
76
+ React.createElement(CardHeader, null,
77
+ React.createElement("div", { className: "flex justify-between" },
78
+ React.createElement("div", { className: "flex gap-3" },
79
+ React.createElement(CardTitle, { className: "text-lg" }, t("dashboard:latestOrders")),
80
+ React.createElement(Button, { size: "icon", variant: "outline", className: "mb-px size-7", onClick: () => {
81
+ setIsLoading(true);
82
+ getOrders();
83
+ } },
84
+ React.createElement(RefreshCw, { size: 16, className: `transition-transform duration-500 ${isLoading ? "animate-spin" : ""}` }))),
85
+ React.createElement(NavLink, { to: Routes.orders.list },
86
+ React.createElement(Button, { className: "relative top-2 -mt-3", variant: "ghost" }, t("dashboard:showAll"))))),
87
+ React.createElement(Separator, { className: "mb-3" }),
88
+ React.createElement(CardContent, null,
89
+ React.createElement(Table, null,
90
+ React.createElement(TableHeader, null, table.getHeaderGroups().map((headerGroup) => (React.createElement(TableRow, { key: headerGroup.id }, headerGroup.headers.map((header) => {
91
+ return (React.createElement(TableHead, { key: header.id }, header.isPlaceholder
92
+ ? null
93
+ : flexRender(header.column.columnDef.header, header.getContext())));
94
+ }))))),
95
+ React.createElement(TableBody, null, table.getRowModel().rows?.length ? (table.getRowModel().rows.map((row) => (React.createElement(TableRow, { key: row.id, "data-state": row.getIsSelected() && "selected" }, row.getAllCells().map((cell) => (React.createElement(TableCell, { className: "py-4", key: cell.id }, flexRender(cell.column.columnDef.cell, cell.getContext())))))))) : (React.createElement(EmptyState, { columnsLength: columns.length, title: t("emptyDataTitle"), description: t("emptyData") })))))));
96
+ };
@@ -0,0 +1,6 @@
1
+ export declare enum PaymentMethod {
2
+ Przelewy24 = "przelewy24",
3
+ Standard = "standard-payment",
4
+ Transfer = "przelew-bankowy",
5
+ OnDelivery = "gotowka-za-pobraniem"
6
+ }
@@ -0,0 +1,7 @@
1
+ export var PaymentMethod;
2
+ (function (PaymentMethod) {
3
+ PaymentMethod["Przelewy24"] = "przelewy24";
4
+ PaymentMethod["Standard"] = "standard-payment";
5
+ PaymentMethod["Transfer"] = "przelew-bankowy";
6
+ PaymentMethod["OnDelivery"] = "gotowka-za-pobraniem";
7
+ })(PaymentMethod || (PaymentMethod = {}));
@@ -0,0 +1,18 @@
1
+ import { TooltipProps } from "recharts";
2
+ import { NameType, ValueType } from "recharts/types/component/DefaultTooltipContent";
3
+ import React from "react";
4
+ import { CurrencyCode } from "@deenruv/admin-types";
5
+ interface CustomTooltipProps {
6
+ chartProps: TooltipProps<ValueType, NameType>;
7
+ language: string;
8
+ selectedAvailableProducts: {
9
+ id: string;
10
+ color: string;
11
+ }[];
12
+ shouldShowCompare: boolean;
13
+ valueStroke: string;
14
+ prevValueStroke: string;
15
+ currencyCode?: CurrencyCode;
16
+ }
17
+ export declare const CustomTooltip: React.FC<CustomTooltipProps>;
18
+ export {};
@@ -0,0 +1,92 @@
1
+ import { Card, CardContent, CardDescription, CardHeader, cn, useTranslation, } from "@deenruv/react-ui-devkit";
2
+ import { ChartMetricType } from "../../zeus";
3
+ import React from "react";
4
+ import { CurrencyCode } from "@deenruv/admin-types";
5
+ import { RatioBadge } from "./RatioBadge";
6
+ import { calculatePercentage } from "../../utils";
7
+ const metricTypeLabels = {
8
+ [ChartMetricType.AverageOrderValue]: "averageOrderValue",
9
+ [ChartMetricType.OrderCount]: "orderCount",
10
+ [ChartMetricType.OrderTotal]: "orderTotal",
11
+ [ChartMetricType.OrderTotalProductsCount]: "orderTotalProductsCount",
12
+ };
13
+ export const CustomTooltip = ({ chartProps, language, selectedAvailableProducts, shouldShowCompare, prevValueStroke, valueStroke, currencyCode, }) => {
14
+ const { t } = useTranslation("dashboard-widgets-plugin");
15
+ const payload = chartProps.payload?.[0]?.payload;
16
+ const value = payload?.value;
17
+ const prevValue = payload?.prevValue;
18
+ const additionalData = payload?.additionalData;
19
+ const metricType = payload?.type;
20
+ const labelKey = metricTypeLabels[metricType];
21
+ const currencyFormatter = new Intl.NumberFormat(language === "pl" ? "pl-PL" : "en-GB", {
22
+ style: "currency",
23
+ currency: currencyCode ?? CurrencyCode.PLN,
24
+ });
25
+ const formattedValue = metricType === ChartMetricType.AverageOrderValue ||
26
+ metricType === ChartMetricType.OrderTotal
27
+ ? currencyFormatter.format(value)
28
+ : value;
29
+ const formattedPrevValue = metricType === ChartMetricType.AverageOrderValue ||
30
+ metricType === ChartMetricType.OrderTotal
31
+ ? currencyFormatter.format(prevValue)
32
+ : prevValue;
33
+ return (React.createElement(Card, { className: "bg-muted flex flex-col" },
34
+ React.createElement(CardHeader, { className: "pb-2" },
35
+ React.createElement(CardDescription, { className: "border-muted-foreground flex items-center justify-between border-b pb-2" },
36
+ payload?.name,
37
+ shouldShowCompare ? (React.createElement(RatioBadge, { ratio: +calculatePercentage(value, prevValue).toFixed(2) })) : null),
38
+ React.createElement("div", { className: "flex flex-col gap-2" },
39
+ React.createElement("div", { className: "flex items-center gap-2 !text-xl" },
40
+ shouldShowCompare ? (React.createElement("div", { className: "flex items-center pr-1" },
41
+ React.createElement("span", { style: {
42
+ background: valueStroke,
43
+ display: "block",
44
+ width: 14,
45
+ height: 14,
46
+ borderRadius: "100%",
47
+ } }))) : null,
48
+ React.createElement("span", null,
49
+ t(labelKey),
50
+ ": ",
51
+ formattedValue)),
52
+ shouldShowCompare ? (React.createElement("div", { className: "!text-md flex items-center gap-2" },
53
+ React.createElement("div", { className: "flex items-center pr-1" },
54
+ React.createElement("span", { style: {
55
+ background: prevValueStroke,
56
+ display: "block",
57
+ width: 14,
58
+ height: 14,
59
+ borderRadius: "100%",
60
+ } })),
61
+ React.createElement("span", null,
62
+ t("previous"),
63
+ ": ",
64
+ formattedPrevValue))) : null)),
65
+ React.createElement(CardContent, null, additionalData
66
+ ?.filter((d) => selectedAvailableProducts?.length
67
+ ? selectedAvailableProducts?.some((sap) => sap.id === d.id)
68
+ : true)
69
+ ?.sort((a, b) => b.quantity - a.quantity)
70
+ ?.map((d) => {
71
+ const isSelected = selectedAvailableProducts.some((p) => p.id === d.id);
72
+ const color = selectedAvailableProducts.find((p) => p.id === d.id)?.color;
73
+ return (React.createElement("div", { key: d.id, className: "flex justify-between gap-4" },
74
+ React.createElement("div", { style: {
75
+ color,
76
+ }, className: cn("flex items-center gap-1 ", !isSelected && "text-muted-foreground") },
77
+ isSelected ? (React.createElement("div", { className: "flex items-center pr-1" },
78
+ React.createElement("span", { style: {
79
+ background: color,
80
+ display: "block",
81
+ width: 14,
82
+ height: 2,
83
+ } }))) : null,
84
+ React.createElement("span", null, d.name),
85
+ React.createElement("span", { className: "opacity-70" },
86
+ `( ${t("variantID")}: ${d.id} ) `,
87
+ ":")),
88
+ React.createElement("span", { style: {
89
+ color,
90
+ } }, d.quantity)));
91
+ }))));
92
+ };
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ import { GroupBy } from "../../types";
3
+ interface GroupBySelectProps {
4
+ value?: GroupBy;
5
+ changeGroupBy: (groupBy: GroupBy) => void;
6
+ }
7
+ export declare const GroupBySelect: React.FC<GroupBySelectProps>;
8
+ export {};
@@ -0,0 +1,17 @@
1
+ import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from "@deenruv/react-ui-devkit";
2
+ import React from "react";
3
+ import { useTranslation } from "react-i18next";
4
+ export const GroupBySelect = ({ changeGroupBy, value, }) => {
5
+ const { t } = useTranslation("dashboard-widgets-plugin", {
6
+ i18n: window.__DEENRUV_SETTINGS__.i18n,
7
+ });
8
+ return (React.createElement(Select, { value: value, onValueChange: (value) => changeGroupBy(value), defaultValue: "day" },
9
+ React.createElement(SelectTrigger, { className: "h-[30px] w-full text-[13px]" },
10
+ React.createElement(SelectValue, { placeholder: t("groupBy") })),
11
+ React.createElement(SelectContent, { className: "max-h-none w-full" },
12
+ React.createElement(SelectGroup, null,
13
+ React.createElement(SelectItem, { value: "day" }, t("byDay")),
14
+ React.createElement(SelectItem, { value: "week" }, t("byWeek")),
15
+ React.createElement(SelectItem, { value: "quarter" }, t("byQuarter")),
16
+ React.createElement(SelectItem, { value: "month" }, t("byMonth"))))));
17
+ };
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ interface MetricsCustomDatesProps {
3
+ startDate: Date | undefined;
4
+ endDate: Date | undefined;
5
+ setDate: (date: Date | undefined, key: "start" | "end") => void;
6
+ isVisible: boolean;
7
+ }
8
+ export declare const MetricsCustomDates: React.FC<MetricsCustomDatesProps>;
9
+ export {};
@@ -0,0 +1,27 @@
1
+ import { Button, Calendar, cn, Popover, PopoverContent, PopoverTrigger, } from "@deenruv/react-ui-devkit";
2
+ import { endOfDay, format, startOfDay } from "date-fns";
3
+ import { CalendarIcon } from "lucide-react";
4
+ import React from "react";
5
+ import { useTranslation } from "react-i18next";
6
+ export const MetricsCustomDates = ({ endDate, startDate, setDate, isVisible, }) => {
7
+ const { t } = useTranslation("dashboard-widgets-plugin", {
8
+ i18n: window.__DEENRUV_SETTINGS__.i18n,
9
+ });
10
+ if (!isVisible)
11
+ return null;
12
+ return (React.createElement("div", { className: "!mt-0 flex gap-2" },
13
+ React.createElement(Popover, null,
14
+ React.createElement(PopoverTrigger, { asChild: true },
15
+ React.createElement(Button, { variant: "outline", className: cn("h-[30px] w-full max-w-[240px] justify-start text-left text-[13px] font-normal", !startDate && "text-muted-foreground") },
16
+ React.createElement(CalendarIcon, { className: "mr-2 size-4" }),
17
+ startDate ? (format(startDate, "PPP")) : (React.createElement("span", null, t("chooseStartDate"))))),
18
+ React.createElement(PopoverContent, { className: "w-auto p-0" },
19
+ React.createElement(Calendar, { mode: "single", selected: startDate, onSelect: (e) => setDate(e ? startOfDay(e) : e, "start"), initialFocus: true }))),
20
+ React.createElement(Popover, null,
21
+ React.createElement(PopoverTrigger, { asChild: true },
22
+ React.createElement(Button, { variant: "outline", className: cn("h-[30px] w-full max-w-[240px] justify-start text-left text-[13px] font-normal", !endDate && "text-muted-foreground") },
23
+ React.createElement(CalendarIcon, { className: "mr-2 size-4" }),
24
+ endDate ? (format(endDate, "PPP")) : (React.createElement("span", null, t("chooseEndDate"))))),
25
+ React.createElement(PopoverContent, { className: "w-auto p-0" },
26
+ React.createElement(Calendar, { mode: "single", selected: endDate, onSelect: (e) => setDate(e ? endOfDay(e) : e, "end"), initialFocus: true })))));
27
+ };
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ import { ChartMetricType } from "../../zeus";
3
+ interface MetricTypeSelectProps {
4
+ changeMetricType: (type: ChartMetricType) => void;
5
+ metricType: ChartMetricType;
6
+ loading: boolean;
7
+ }
8
+ export declare const MetricTypeSelect: React.FC<MetricTypeSelectProps>;
9
+ export {};
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ import { ChartMetricType } from "../../zeus";
3
+ import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, Skeleton, useTranslation, } from "@deenruv/react-ui-devkit";
4
+ export const MetricTypeSelect = ({ changeMetricType, metricType, loading, }) => {
5
+ const { t } = useTranslation("dashboard-widgets-plugin");
6
+ return (React.createElement("div", { className: "relative w-full max-w-[240px]" },
7
+ loading ? (React.createElement(Skeleton, { className: "absolute left-0 top-0 size-full" })) : null,
8
+ React.createElement(Select, { value: metricType, onValueChange: (value) => changeMetricType(value), defaultValue: ChartMetricType.OrderTotal },
9
+ React.createElement(SelectTrigger, { className: "text-[13px]" },
10
+ React.createElement(SelectValue, { placeholder: t("selectDataType") })),
11
+ React.createElement(SelectContent, { className: "w-full" },
12
+ React.createElement(SelectGroup, null,
13
+ React.createElement(SelectItem, { value: ChartMetricType.AverageOrderValue }, t("averageOrderValue")),
14
+ React.createElement(SelectItem, { value: ChartMetricType.OrderCount }, t("orderCount")),
15
+ React.createElement(SelectItem, { value: ChartMetricType.OrderTotal }, t("orderTotal")),
16
+ React.createElement(SelectItem, { value: ChartMetricType.OrderTotalProductsCount }, t("orderTotalProductsCount")))))));
17
+ };
@@ -0,0 +1,24 @@
1
+ import React from "react";
2
+ import { ChartMetricType } from "../../zeus";
3
+ interface ChartProps {
4
+ data: {
5
+ [key: string]: any;
6
+ name: string;
7
+ value?: number;
8
+ type: ChartMetricType;
9
+ }[];
10
+ language: string;
11
+ options?: {
12
+ colorFrom?: string;
13
+ colorTo?: string;
14
+ stroke?: string;
15
+ };
16
+ selectedAvailableProducts: {
17
+ id: string;
18
+ color: string;
19
+ }[];
20
+ metricType: ChartMetricType;
21
+ shouldShowCompare: boolean;
22
+ }
23
+ export declare const OrdersChart: React.FC<ChartProps>;
24
+ export {};
@@ -0,0 +1,46 @@
1
+ import { Area, CartesianGrid, ComposedChart, Line, XAxis, YAxis, } from "recharts";
2
+ import React, { useMemo } from "react";
3
+ import { ChartMetricType } from "../../zeus";
4
+ import { camelCaseToSpaces, priceFormatter, useSettings, useWidgetItem, } from "@deenruv/react-ui-devkit";
5
+ import { CustomTooltip } from "./CustomTooltip";
6
+ import { ChartContainer, ChartTooltip, } from "@deenruv/react-ui-devkit";
7
+ import { CurrencyCode } from "@deenruv/admin-types";
8
+ const HEIGHT = 300;
9
+ export const OrdersChart = ({ data, language, selectedAvailableProducts, metricType, options: _options, shouldShowCompare, }) => {
10
+ const chartConfig = useMemo(() => {
11
+ return { value: { label: camelCaseToSpaces(data[0]?.type) } };
12
+ }, [data]);
13
+ const currencyCode = useSettings((p) => p.selectedChannel?.currencyCode);
14
+ const { plugin } = useWidgetItem();
15
+ // @ts-expect-error: for now we dont have types, we now that this is working
16
+ const options = plugin?.config.options
17
+ ?.horizontalChartColors || {
18
+ colorFrom: `#4338ca`,
19
+ colorTo: `#6366f1`,
20
+ stroke: `#6366f1`,
21
+ };
22
+ return (React.createElement(ChartContainer, { config: chartConfig, style: { height: `${HEIGHT}px`, width: "100%" } },
23
+ React.createElement(ComposedChart, { height: HEIGHT, accessibilityLayer: true, data: data, margin: {
24
+ left: 62,
25
+ } },
26
+ React.createElement(CartesianGrid, { vertical: false }),
27
+ React.createElement(XAxis, { dataKey: "name", tickLine: false, axisLine: false, tickMargin: 12 }),
28
+ React.createElement(YAxis, { tickLine: false, axisLine: false, tickMargin: 4, tickFormatter: (value) => metricType === ChartMetricType.OrderCount ||
29
+ metricType === ChartMetricType.OrderTotalProductsCount
30
+ ? value
31
+ : priceFormatter((value ?? 0) * 100, currencyCode ?? CurrencyCode.PLN) }),
32
+ React.createElement(ChartTooltip, { wrapperStyle: { zIndex: 1000 }, cursor: false, content: (p) => (React.createElement(CustomTooltip, { currencyCode: currencyCode, valueStroke: options.stroke, prevValueStroke: "#82FF9E", shouldShowCompare: shouldShowCompare, selectedAvailableProducts: selectedAvailableProducts, chartProps: p, language: language })) }),
33
+ React.createElement("defs", null,
34
+ React.createElement("linearGradient", { id: "fill", x1: "0", y1: "0", x2: "0", y2: "1" },
35
+ React.createElement("stop", { offset: "0%", stopColor: options.colorFrom, stopOpacity: 0.9 }),
36
+ React.createElement("stop", { offset: "100%", stopColor: options.colorTo, stopOpacity: 0.2 })),
37
+ React.createElement("linearGradient", { id: "fillPrev", x1: "0", y1: "0", x2: "0", y2: "1" },
38
+ React.createElement("stop", { offset: "5%", stopColor: "#82FF9E", stopOpacity: 0.5 }),
39
+ React.createElement("stop", { offset: "95%", stopColor: "#82FF9E", stopOpacity: 0 }))),
40
+ " ",
41
+ shouldShowCompare ? (React.createElement(Area, { dataKey: selectedAvailableProducts.length ? "no-value" : "prevValue", strokeWidth: 0.1, type: "monotone", fill: "url(#fillPrev)", fillOpacity: 0.4, stroke: "#82FF9E", stackId: "a" })) : null,
42
+ React.createElement(Area, { dataKey: selectedAvailableProducts.length ? "no-value" : "value", type: "monotone", fill: "url(#fill)", fillOpacity: shouldShowCompare ? 0.6 : 0.4, stroke: options.stroke, stackId: "b" }),
43
+ selectedAvailableProducts.length
44
+ ? selectedAvailableProducts.map((selectedProduct) => (React.createElement(Line, { type: "monotone", dot: false, stroke: selectedProduct.color, key: selectedProduct.id, dataKey: selectedProduct.id })))
45
+ : null)));
46
+ };
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import { DateRangeType } from "../../types";
3
+ interface OrdersSummaryTileProps {
4
+ net?: boolean;
5
+ setNet: (net: boolean) => void;
6
+ dateRange: {
7
+ range: DateRangeType;
8
+ prevRange: DateRangeType;
9
+ };
10
+ orderStates: string[];
11
+ }
12
+ export declare const OrdersSummaryTile: React.FC<OrdersSummaryTileProps>;
13
+ export {};