@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.
- package/LICENSE +23 -0
- package/README.md +58 -0
- package/dist/plugin-server/constants.d.ts +4 -0
- package/dist/plugin-server/constants.js +12 -0
- package/dist/plugin-server/controllers/admin-ui-controller.d.ts +4 -0
- package/dist/plugin-server/controllers/admin-ui-controller.js +46 -0
- package/dist/plugin-server/controllers/refresh-view-controller.d.ts +8 -0
- package/dist/plugin-server/controllers/refresh-view-controller.js +41 -0
- package/dist/plugin-server/index.d.ts +1 -0
- package/dist/plugin-server/index.js +17 -0
- package/dist/plugin-server/materialisedViewEntities/order_summary.d.ts +9 -0
- package/dist/plugin-server/materialisedViewEntities/order_summary.js +79 -0
- package/dist/plugin-server/materialisedViewEntities/orders_summary_with_state.d.ts +10 -0
- package/dist/plugin-server/materialisedViewEntities/orders_summary_with_state.js +79 -0
- package/dist/plugin-server/materialisedViewEntities/total_products.d.ts +7 -0
- package/dist/plugin-server/materialisedViewEntities/total_products.js +62 -0
- package/dist/plugin-server/materialisedViewEntities/total_products_with_state.d.ts +9 -0
- package/dist/plugin-server/materialisedViewEntities/total_products_with_state.js +62 -0
- package/dist/plugin-server/plugin.d.ts +6 -0
- package/dist/plugin-server/plugin.js +149 -0
- package/dist/plugin-server/raw-sql.d.ts +8 -0
- package/dist/plugin-server/raw-sql.js +48 -0
- package/dist/plugin-server/resolvers/admin.resolver.d.ts +47 -0
- package/dist/plugin-server/resolvers/admin.resolver.js +63 -0
- package/dist/plugin-server/services/metrics.service.d.ts +30 -0
- package/dist/plugin-server/services/metrics.service.js +272 -0
- package/dist/plugin-server/types.d.ts +20 -0
- package/dist/plugin-server/types.js +2 -0
- package/dist/plugin-server/utils.d.ts +1 -0
- package/dist/plugin-server/utils.js +12 -0
- package/dist/plugin-server/zeus/const.d.ts +6 -0
- package/dist/plugin-server/zeus/const.js +3675 -0
- package/dist/plugin-server/zeus/index.d.ts +18709 -0
- package/dist/plugin-server/zeus/index.js +1122 -0
- package/dist/plugin-server/zeus/typedDocumentNode.d.ts +3 -0
- package/dist/plugin-server/zeus/typedDocumentNode.js +16 -0
- package/dist/plugin-ui/components/CategoriesChartWidget/dashCaseToSpaces.d.ts +1 -0
- package/dist/plugin-ui/components/CategoriesChartWidget/dashCaseToSpaces.js +6 -0
- package/dist/plugin-ui/components/CategoriesChartWidget/index.d.ts +2 -0
- package/dist/plugin-ui/components/CategoriesChartWidget/index.js +100 -0
- package/dist/plugin-ui/components/LatestOrdersWidget/index.d.ts +4 -0
- package/dist/plugin-ui/components/LatestOrdersWidget/index.js +96 -0
- package/dist/plugin-ui/components/LatestOrdersWidget/paymentMethod.d.ts +6 -0
- package/dist/plugin-ui/components/LatestOrdersWidget/paymentMethod.js +7 -0
- package/dist/plugin-ui/components/OrdersWidget/CustomTooltip.d.ts +18 -0
- package/dist/plugin-ui/components/OrdersWidget/CustomTooltip.js +92 -0
- package/dist/plugin-ui/components/OrdersWidget/GroupBySelect.d.ts +8 -0
- package/dist/plugin-ui/components/OrdersWidget/GroupBySelect.js +17 -0
- package/dist/plugin-ui/components/OrdersWidget/MetricCustomDates.d.ts +9 -0
- package/dist/plugin-ui/components/OrdersWidget/MetricCustomDates.js +27 -0
- package/dist/plugin-ui/components/OrdersWidget/MetricTypeSelect.d.ts +9 -0
- package/dist/plugin-ui/components/OrdersWidget/MetricTypeSelect.js +17 -0
- package/dist/plugin-ui/components/OrdersWidget/OrdersChart.d.ts +24 -0
- package/dist/plugin-ui/components/OrdersWidget/OrdersChart.js +46 -0
- package/dist/plugin-ui/components/OrdersWidget/OrdersSummaryTile.d.ts +13 -0
- package/dist/plugin-ui/components/OrdersWidget/OrdersSummaryTile.js +115 -0
- package/dist/plugin-ui/components/OrdersWidget/ProductSelector.d.ts +17 -0
- package/dist/plugin-ui/components/OrdersWidget/ProductSelector.js +37 -0
- package/dist/plugin-ui/components/OrdersWidget/RatioBadge.d.ts +6 -0
- package/dist/plugin-ui/components/OrdersWidget/RatioBadge.js +12 -0
- package/dist/plugin-ui/components/OrdersWidget/index.d.ts +2 -0
- package/dist/plugin-ui/components/OrdersWidget/index.js +229 -0
- package/dist/plugin-ui/components/ProductsChartWidget/CustomBarChartTooltip.d.ts +9 -0
- package/dist/plugin-ui/components/ProductsChartWidget/CustomBarChartTooltip.js +14 -0
- package/dist/plugin-ui/components/ProductsChartWidget/index.d.ts +2 -0
- package/dist/plugin-ui/components/ProductsChartWidget/index.js +116 -0
- package/dist/plugin-ui/components/index.d.ts +4 -0
- package/dist/plugin-ui/components/index.js +4 -0
- package/dist/plugin-ui/components/shared/EmptyData.d.ts +6 -0
- package/dist/plugin-ui/components/shared/EmptyData.js +8 -0
- package/dist/plugin-ui/components/shared/MetricsRangeSelect.d.ts +10 -0
- package/dist/plugin-ui/components/shared/MetricsRangeSelect.js +26 -0
- package/dist/plugin-ui/components/shared/OrderStatesSelect.d.ts +8 -0
- package/dist/plugin-ui/components/shared/OrderStatesSelect.js +28 -0
- package/dist/plugin-ui/components/shared/PeriodSelect.d.ts +20 -0
- package/dist/plugin-ui/components/shared/PeriodSelect.js +56 -0
- package/dist/plugin-ui/components/shared/colors.d.ts +1 -0
- package/dist/plugin-ui/components/shared/colors.js +1 -0
- package/dist/plugin-ui/components/shared/index.d.ts +3 -0
- package/dist/plugin-ui/components/shared/index.js +3 -0
- package/dist/plugin-ui/graphql/index.d.ts +2 -0
- package/dist/plugin-ui/graphql/index.js +2 -0
- package/dist/plugin-ui/graphql/queries.d.ts +425 -0
- package/dist/plugin-ui/graphql/queries.js +182 -0
- package/dist/plugin-ui/graphql/selectors.d.ts +19 -0
- package/dist/plugin-ui/graphql/selectors.js +21 -0
- package/dist/plugin-ui/index.d.ts +9 -0
- package/dist/plugin-ui/index.js +21 -0
- package/dist/plugin-ui/locales/en/index.d.ts +72 -0
- package/dist/plugin-ui/locales/en/index.js +2 -0
- package/dist/plugin-ui/locales/en/test.json +71 -0
- package/dist/plugin-ui/locales/pl/index.d.ts +71 -0
- package/dist/plugin-ui/locales/pl/index.js +2 -0
- package/dist/plugin-ui/locales/pl/test.json +70 -0
- package/dist/plugin-ui/tsconfig.json +18 -0
- package/dist/plugin-ui/types.d.ts +64 -0
- package/dist/plugin-ui/types.js +14 -0
- package/dist/plugin-ui/utils.d.ts +70 -0
- package/dist/plugin-ui/utils.js +366 -0
- package/dist/plugin-ui/widgets.d.ts +15 -0
- package/dist/plugin-ui/widgets.js +36 -0
- package/dist/plugin-ui/zeus/const.d.ts +6 -0
- package/dist/plugin-ui/zeus/const.js +3672 -0
- package/dist/plugin-ui/zeus/index.d.ts +18709 -0
- package/dist/plugin-ui/zeus/index.js +1114 -0
- package/dist/plugin-ui/zeus/typedDocumentNode.d.ts +3 -0
- package/dist/plugin-ui/zeus/typedDocumentNode.js +9 -0
- 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,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,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,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,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 {};
|