@open-mercato/ui 0.6.4-develop.3944.1.4100aa7fbe → 0.6.4-develop.3962.1.70f30e284c
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/.turbo/turbo-build.log +1 -1
- package/dist/ai/AiChat.js +4 -2
- package/dist/ai/AiChat.js.map +2 -2
- package/dist/ai/AiChatSessions.js +30 -9
- package/dist/ai/AiChatSessions.js.map +2 -2
- package/dist/ai/AiDock.js +6 -1
- package/dist/ai/AiDock.js.map +2 -2
- package/dist/ai/conversation-store.js +2 -1
- package/dist/ai/conversation-store.js.map +2 -2
- package/dist/ai/useAiChat.js +15 -4
- package/dist/ai/useAiChat.js.map +2 -2
- package/dist/backend/charts/BarChart.js +19 -76
- package/dist/backend/charts/BarChart.js.map +2 -2
- package/dist/backend/charts/BarChartImpl.js +91 -0
- package/dist/backend/charts/BarChartImpl.js.map +7 -0
- package/dist/backend/charts/LineChart.js +18 -91
- package/dist/backend/charts/LineChart.js.map +2 -2
- package/dist/backend/charts/LineChartImpl.js +112 -0
- package/dist/backend/charts/LineChartImpl.js.map +7 -0
- package/dist/backend/charts/PieChart.js +17 -62
- package/dist/backend/charts/PieChart.js.map +2 -2
- package/dist/backend/charts/PieChartImpl.js +76 -0
- package/dist/backend/charts/PieChartImpl.js.map +7 -0
- package/dist/backend/dashboard/DashboardScreen.js +9 -1
- package/dist/backend/dashboard/DashboardScreen.js.map +2 -2
- package/dist/backend/dashboard/widgetRegistry.js +18 -2
- package/dist/backend/dashboard/widgetRegistry.js.map +2 -2
- package/dist/backend/injection/useInjectionDataWidgets.js +12 -2
- package/dist/backend/injection/useInjectionDataWidgets.js.map +2 -2
- package/package.json +3 -3
- package/src/ai/AiChat.tsx +10 -0
- package/src/ai/AiChatSessions.tsx +54 -9
- package/src/ai/AiDock.tsx +11 -0
- package/src/ai/__tests__/AiChat.conversation.test.tsx +97 -0
- package/src/ai/__tests__/AiChatSessions.test.tsx +228 -0
- package/src/ai/__tests__/AiDock.test.tsx +31 -1
- package/src/ai/__tests__/conversation-store.test.ts +74 -1
- package/src/ai/conversation-store.ts +18 -2
- package/src/ai/useAiChat.ts +35 -4
- package/src/backend/__tests__/lazy-heavy-libraries.test.ts +53 -0
- package/src/backend/charts/BarChart.tsx +21 -72
- package/src/backend/charts/BarChartImpl.tsx +99 -0
- package/src/backend/charts/LineChart.tsx +23 -85
- package/src/backend/charts/LineChartImpl.tsx +120 -0
- package/src/backend/charts/PieChart.tsx +19 -60
- package/src/backend/charts/PieChartImpl.tsx +82 -0
- package/src/backend/dashboard/DashboardScreen.tsx +9 -1
- package/src/backend/dashboard/__tests__/DashboardScreen.test.tsx +45 -0
- package/src/backend/dashboard/__tests__/widgetRegistry.test.ts +60 -0
- package/src/backend/dashboard/widgetRegistry.ts +23 -5
- package/src/backend/injection/useInjectionDataWidgets.ts +18 -2
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/backend/charts/BarChartImpl.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {\n BarChart as RechartsBarChart,\n Bar,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n Legend,\n ResponsiveContainer,\n} from 'recharts'\nimport { ChartTooltipContent, resolveChartColor } from './ChartUtils'\nimport type { BarChartDataItem, BarChartProps } from './BarChart'\n\ntype ImplProps = Pick<\n BarChartProps,\n | 'data'\n | 'index'\n | 'categories'\n | 'colors'\n | 'layout'\n | 'valueFormatter'\n | 'showLegend'\n | 'showGridLines'\n | 'categoryLabels'\n> & {\n valueFormatter: (value: number) => string\n}\n\nexport default function BarChartImpl({\n data,\n index,\n categories,\n colors,\n layout = 'vertical',\n valueFormatter,\n showLegend = true,\n showGridLines = true,\n categoryLabels,\n}: ImplProps) {\n const isHorizontal = layout === 'horizontal'\n const chartHeight = isHorizontal ? Math.max(200, data.length * 28) : 200\n const getBarColor = (idx: number): string => resolveChartColor(colors?.[idx], idx)\n\n return (\n <ResponsiveContainer width=\"100%\" height={chartHeight}>\n <RechartsBarChart\n data={data}\n layout={isHorizontal ? 'vertical' : 'horizontal'}\n margin={{ top: 5, right: 30, left: 20, bottom: 5 }}\n >\n {showGridLines && (\n <CartesianGrid strokeDasharray=\"3 3\" stroke=\"hsl(var(--border))\" />\n )}\n <XAxis\n type={isHorizontal ? 'number' : 'category'}\n dataKey={isHorizontal ? undefined : index}\n tickFormatter={isHorizontal ? valueFormatter : undefined}\n tick={{ fontSize: 11 }}\n />\n <YAxis\n type={isHorizontal ? 'category' : 'number'}\n dataKey={isHorizontal ? index : undefined}\n tickFormatter={isHorizontal ? undefined : valueFormatter}\n width={isHorizontal ? 90 : 50}\n interval={0}\n tick={{ fontSize: 10 }}\n />\n <Tooltip\n content={\n <ChartTooltipContent\n valueFormatter={valueFormatter}\n categoryLabels={categoryLabels}\n labelFormatter={(label, payload) => {\n const entry = payload?.[0] as { payload?: BarChartDataItem } | undefined\n const item = entry?.payload\n return item?.[index] ? String(item[index]) : label\n }}\n />\n }\n cursor={{ fill: 'hsl(var(--muted))', opacity: 0.2 }}\n />\n {showLegend && categories.length > 1 && (\n <Legend verticalAlign=\"top\" height={36} />\n )}\n {categories.map((category, idx) => (\n <Bar\n key={category}\n dataKey={category}\n fill={getBarColor(idx)}\n radius={isHorizontal ? [0, 4, 4, 0] : [4, 4, 0, 0]}\n />\n ))}\n </RechartsBarChart>\n </ResponsiveContainer>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAgDM,SAMI,KANJ;AA7CN;AAAA,EACE,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB,yBAAyB;AAkBxC,SAAR,aAA8B;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB;AACF,GAAc;AACZ,QAAM,eAAe,WAAW;AAChC,QAAM,cAAc,eAAe,KAAK,IAAI,KAAK,KAAK,SAAS,EAAE,IAAI;AACrE,QAAM,cAAc,CAAC,QAAwB,kBAAkB,SAAS,GAAG,GAAG,GAAG;AAEjF,SACE,oBAAC,uBAAoB,OAAM,QAAO,QAAQ,aACxC;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,QAAQ,eAAe,aAAa;AAAA,MACpC,QAAQ,EAAE,KAAK,GAAG,OAAO,IAAI,MAAM,IAAI,QAAQ,EAAE;AAAA,MAEhD;AAAA,yBACC,oBAAC,iBAAc,iBAAgB,OAAM,QAAO,sBAAqB;AAAA,QAEnE;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,eAAe,WAAW;AAAA,YAChC,SAAS,eAAe,SAAY;AAAA,YACpC,eAAe,eAAe,iBAAiB;AAAA,YAC/C,MAAM,EAAE,UAAU,GAAG;AAAA;AAAA,QACvB;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,eAAe,aAAa;AAAA,YAClC,SAAS,eAAe,QAAQ;AAAA,YAChC,eAAe,eAAe,SAAY;AAAA,YAC1C,OAAO,eAAe,KAAK;AAAA,YAC3B,UAAU;AAAA,YACV,MAAM,EAAE,UAAU,GAAG;AAAA;AAAA,QACvB;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,SACE;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA,gBAAgB,CAAC,OAAO,YAAY;AAClC,wBAAM,QAAQ,UAAU,CAAC;AACzB,wBAAM,OAAO,OAAO;AACpB,yBAAO,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,CAAC,IAAI;AAAA,gBAC/C;AAAA;AAAA,YACF;AAAA,YAEF,QAAQ,EAAE,MAAM,qBAAqB,SAAS,IAAI;AAAA;AAAA,QACpD;AAAA,QACC,cAAc,WAAW,SAAS,KACjC,oBAAC,UAAO,eAAc,OAAM,QAAQ,IAAI;AAAA,QAEzC,WAAW,IAAI,CAAC,UAAU,QACzB;AAAA,UAAC;AAAA;AAAA,YAEC,SAAS;AAAA,YACT,MAAM,YAAY,GAAG;AAAA,YACrB,QAAQ,eAAe,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,UAH5C;AAAA,QAIP,CACD;AAAA;AAAA;AAAA,EACH,GACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import
|
|
4
|
-
LineChart as RechartsLineChart,
|
|
5
|
-
AreaChart as RechartsAreaChart,
|
|
6
|
-
Line,
|
|
7
|
-
Area,
|
|
8
|
-
XAxis,
|
|
9
|
-
YAxis,
|
|
10
|
-
CartesianGrid,
|
|
11
|
-
Tooltip,
|
|
12
|
-
ResponsiveContainer,
|
|
13
|
-
Legend
|
|
14
|
-
} from "recharts";
|
|
3
|
+
import dynamic from "next/dynamic";
|
|
15
4
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
16
|
-
import { ChartTooltipContent, resolveChartColor } from "./ChartUtils.js";
|
|
17
5
|
function defaultValueFormatter(value) {
|
|
18
6
|
if (Math.abs(value) >= 1e6) {
|
|
19
7
|
return `${(value / 1e6).toFixed(1)}M`;
|
|
@@ -23,6 +11,10 @@ function defaultValueFormatter(value) {
|
|
|
23
11
|
}
|
|
24
12
|
return value.toLocaleString(void 0, { maximumFractionDigits: 2 });
|
|
25
13
|
}
|
|
14
|
+
const LineChartImpl = dynamic(() => import("./LineChartImpl.js"), {
|
|
15
|
+
ssr: false,
|
|
16
|
+
loading: () => /* @__PURE__ */ jsx("div", { className: "flex h-48 items-center justify-center", children: /* @__PURE__ */ jsx(Spinner, { className: "h-6 w-6 text-muted-foreground" }) })
|
|
17
|
+
});
|
|
26
18
|
function LineChart({
|
|
27
19
|
title,
|
|
28
20
|
data,
|
|
@@ -41,9 +33,6 @@ function LineChart({
|
|
|
41
33
|
emptyMessage = "No data available",
|
|
42
34
|
categoryLabels
|
|
43
35
|
}) {
|
|
44
|
-
const getLineColor = (idx) => {
|
|
45
|
-
return resolveChartColor(colors?.[idx], idx);
|
|
46
|
-
};
|
|
47
36
|
if (error) {
|
|
48
37
|
return /* @__PURE__ */ jsxs("div", { className: `rounded-lg border bg-card p-4 ${className}`, children: [
|
|
49
38
|
title && /* @__PURE__ */ jsx("h3", { className: "mb-4 text-base font-medium text-card-foreground", children: title }),
|
|
@@ -62,86 +51,24 @@ function LineChart({
|
|
|
62
51
|
/* @__PURE__ */ jsx("div", { className: "flex h-48 items-center justify-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessage }) })
|
|
63
52
|
] });
|
|
64
53
|
}
|
|
65
|
-
const ChartComponent = showArea ? RechartsAreaChart : RechartsLineChart;
|
|
66
54
|
return /* @__PURE__ */ jsxs("div", { className: `rounded-lg border bg-card p-4 ${className}`, children: [
|
|
67
55
|
title && /* @__PURE__ */ jsx("h3", { className: "mb-4 text-base font-medium text-card-foreground", children: title }),
|
|
68
|
-
/* @__PURE__ */ jsx("div", { className: "h-52 w-full", children: /* @__PURE__ */ jsx(
|
|
69
|
-
|
|
56
|
+
/* @__PURE__ */ jsx("div", { className: "h-52 w-full", children: /* @__PURE__ */ jsx(
|
|
57
|
+
LineChartImpl,
|
|
70
58
|
{
|
|
71
59
|
data,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
XAxis,
|
|
83
|
-
{
|
|
84
|
-
dataKey: index,
|
|
85
|
-
tick: { fontSize: 12 },
|
|
86
|
-
tickLine: false,
|
|
87
|
-
axisLine: false
|
|
88
|
-
}
|
|
89
|
-
),
|
|
90
|
-
/* @__PURE__ */ jsx(
|
|
91
|
-
YAxis,
|
|
92
|
-
{
|
|
93
|
-
tickFormatter: valueFormatter,
|
|
94
|
-
tick: { fontSize: 12 },
|
|
95
|
-
tickLine: false,
|
|
96
|
-
axisLine: false,
|
|
97
|
-
width: 56
|
|
98
|
-
}
|
|
99
|
-
),
|
|
100
|
-
/* @__PURE__ */ jsx(
|
|
101
|
-
Tooltip,
|
|
102
|
-
{
|
|
103
|
-
content: /* @__PURE__ */ jsx(ChartTooltipContent, { valueFormatter, categoryLabels }),
|
|
104
|
-
cursor: { stroke: "hsl(var(--muted-foreground))", strokeDasharray: "3 3" }
|
|
105
|
-
}
|
|
106
|
-
),
|
|
107
|
-
showLegend && categories.length > 1 && /* @__PURE__ */ jsx(
|
|
108
|
-
Legend,
|
|
109
|
-
{
|
|
110
|
-
verticalAlign: "top",
|
|
111
|
-
height: 36,
|
|
112
|
-
formatter: (value) => /* @__PURE__ */ jsx("span", { style: { color: "hsl(var(--muted-foreground))", fontSize: "12px" }, children: value })
|
|
113
|
-
}
|
|
114
|
-
),
|
|
115
|
-
showArea ? categories.map((category, idx) => /* @__PURE__ */ jsx(
|
|
116
|
-
Area,
|
|
117
|
-
{
|
|
118
|
-
type: curveType,
|
|
119
|
-
dataKey: category,
|
|
120
|
-
stroke: getLineColor(idx),
|
|
121
|
-
fill: getLineColor(idx),
|
|
122
|
-
fillOpacity: 0.2,
|
|
123
|
-
strokeWidth: 2,
|
|
124
|
-
connectNulls,
|
|
125
|
-
dot: false,
|
|
126
|
-
activeDot: { r: 4, strokeWidth: 0 }
|
|
127
|
-
},
|
|
128
|
-
category
|
|
129
|
-
)) : categories.map((category, idx) => /* @__PURE__ */ jsx(
|
|
130
|
-
Line,
|
|
131
|
-
{
|
|
132
|
-
type: curveType,
|
|
133
|
-
dataKey: category,
|
|
134
|
-
stroke: getLineColor(idx),
|
|
135
|
-
strokeWidth: 2,
|
|
136
|
-
connectNulls,
|
|
137
|
-
dot: false,
|
|
138
|
-
activeDot: { r: 4, strokeWidth: 0 }
|
|
139
|
-
},
|
|
140
|
-
category
|
|
141
|
-
))
|
|
142
|
-
]
|
|
60
|
+
index,
|
|
61
|
+
categories,
|
|
62
|
+
colors,
|
|
63
|
+
showArea,
|
|
64
|
+
valueFormatter,
|
|
65
|
+
showLegend,
|
|
66
|
+
showGridLines,
|
|
67
|
+
curveType,
|
|
68
|
+
connectNulls,
|
|
69
|
+
categoryLabels
|
|
143
70
|
}
|
|
144
|
-
) })
|
|
71
|
+
) })
|
|
145
72
|
] });
|
|
146
73
|
}
|
|
147
74
|
var LineChart_default = LineChart;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/charts/LineChart.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport dynamic from 'next/dynamic'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\n\nexport type LineChartDataItem = Record<string, string | number | null | undefined>\n\nexport type LineChartProps = {\n title?: string\n data: LineChartDataItem[]\n index: string\n categories: string[]\n loading?: boolean\n error?: string | null\n colors?: string[]\n showArea?: boolean\n valueFormatter?: (value: number) => string\n showLegend?: boolean\n showGridLines?: boolean\n curveType?: 'linear' | 'natural' | 'monotone' | 'step'\n connectNulls?: boolean\n className?: string\n emptyMessage?: string\n categoryLabels?: Record<string, string>\n}\n\nfunction defaultValueFormatter(value: number): string {\n if (Math.abs(value) >= 1_000_000) {\n return `${(value / 1_000_000).toFixed(1)}M`\n }\n if (Math.abs(value) >= 1_000) {\n return `${(value / 1_000).toFixed(1)}K`\n }\n return value.toLocaleString(undefined, { maximumFractionDigits: 2 })\n}\n\nconst LineChartImpl = dynamic(() => import('./LineChartImpl'), {\n ssr: false,\n loading: () => (\n <div className=\"flex h-48 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n ),\n})\n\nexport function LineChart({\n title,\n data,\n index,\n categories,\n loading,\n error,\n colors,\n showArea = false,\n valueFormatter = defaultValueFormatter,\n showLegend = true,\n showGridLines = true,\n curveType = 'monotone',\n connectNulls = true,\n className = '',\n emptyMessage = 'No data available',\n categoryLabels,\n}: LineChartProps) {\n if (error) {\n return (\n <div className={`rounded-lg border bg-card p-4 ${className}`}>\n {title && <h3 className=\"mb-4 text-base font-medium text-card-foreground\">{title}</h3>}\n <div className=\"flex h-48 items-center justify-center\">\n <p className=\"text-sm text-destructive\">{error}</p>\n </div>\n </div>\n )\n }\n\n if (loading) {\n return (\n <div className={`rounded-lg border bg-card p-4 ${className}`}>\n {title && <h3 className=\"mb-4 text-base font-medium text-card-foreground\">{title}</h3>}\n <div className=\"flex h-48 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n </div>\n )\n }\n\n if (!data || data.length === 0) {\n return (\n <div className={`rounded-lg border bg-card p-4 ${className}`}>\n {title && <h3 className=\"mb-4 text-base font-medium text-card-foreground\">{title}</h3>}\n <div className=\"flex h-48 items-center justify-center\">\n <p className=\"text-sm text-muted-foreground\">{emptyMessage}</p>\n </div>\n </div>\n )\n }\n\n return (\n <div className={`rounded-lg border bg-card p-4 ${className}`}>\n {title && <h3 className=\"mb-4 text-base font-medium text-card-foreground\">{title}</h3>}\n <div className=\"h-52 w-full\">\n <LineChartImpl\n data={data}\n index={index}\n categories={categories}\n colors={colors}\n showArea={showArea}\n valueFormatter={valueFormatter}\n showLegend={showLegend}\n showGridLines={showGridLines}\n curveType={curveType}\n connectNulls={connectNulls}\n categoryLabels={categoryLabels}\n />\n </div>\n </div>\n )\n}\n\nexport default LineChart\n"],
|
|
5
|
+
"mappings": ";AAyCM,cAyBA,YAzBA;AAtCN,OAAO,aAAa;AACpB,SAAS,eAAe;AAuBxB,SAAS,sBAAsB,OAAuB;AACpD,MAAI,KAAK,IAAI,KAAK,KAAK,KAAW;AAChC,WAAO,IAAI,QAAQ,KAAW,QAAQ,CAAC,CAAC;AAAA,EAC1C;AACA,MAAI,KAAK,IAAI,KAAK,KAAK,KAAO;AAC5B,WAAO,IAAI,QAAQ,KAAO,QAAQ,CAAC,CAAC;AAAA,EACtC;AACA,SAAO,MAAM,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC;AACrE;AAEA,MAAM,gBAAgB,QAAQ,MAAM,OAAO,iBAAiB,GAAG;AAAA,EAC7D,KAAK;AAAA,EACL,SAAS,MACP,oBAAC,SAAI,WAAU,yCACb,8BAAC,WAAQ,WAAU,iCAAgC,GACrD;AAEJ,CAAC;AAEM,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,eAAe;AAAA,EACf;AACF,GAAmB;AACjB,MAAI,OAAO;AACT,WACE,qBAAC,SAAI,WAAW,iCAAiC,SAAS,IACvD;AAAA,eAAS,oBAAC,QAAG,WAAU,mDAAmD,iBAAM;AAAA,MACjF,oBAAC,SAAI,WAAU,yCACb,8BAAC,OAAE,WAAU,4BAA4B,iBAAM,GACjD;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,qBAAC,SAAI,WAAW,iCAAiC,SAAS,IACvD;AAAA,eAAS,oBAAC,QAAG,WAAU,mDAAmD,iBAAM;AAAA,MACjF,oBAAC,SAAI,WAAU,yCACb,8BAAC,WAAQ,WAAU,iCAAgC,GACrD;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAC9B,WACE,qBAAC,SAAI,WAAW,iCAAiC,SAAS,IACvD;AAAA,eAAS,oBAAC,QAAG,WAAU,mDAAmD,iBAAM;AAAA,MACjF,oBAAC,SAAI,WAAU,yCACb,8BAAC,OAAE,WAAU,iCAAiC,wBAAa,GAC7D;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAW,iCAAiC,SAAS,IACvD;AAAA,aAAS,oBAAC,QAAG,WAAU,mDAAmD,iBAAM;AAAA,IACjF,oBAAC,SAAI,WAAU,eACb;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;AAEA,IAAO,oBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import {
|
|
4
|
+
LineChart as RechartsLineChart,
|
|
5
|
+
AreaChart as RechartsAreaChart,
|
|
6
|
+
Line,
|
|
7
|
+
Area,
|
|
8
|
+
XAxis,
|
|
9
|
+
YAxis,
|
|
10
|
+
CartesianGrid,
|
|
11
|
+
Tooltip,
|
|
12
|
+
ResponsiveContainer,
|
|
13
|
+
Legend
|
|
14
|
+
} from "recharts";
|
|
15
|
+
import { ChartTooltipContent, resolveChartColor } from "./ChartUtils.js";
|
|
16
|
+
function LineChartImpl({
|
|
17
|
+
data,
|
|
18
|
+
index,
|
|
19
|
+
categories,
|
|
20
|
+
colors,
|
|
21
|
+
showArea = false,
|
|
22
|
+
valueFormatter,
|
|
23
|
+
showLegend = true,
|
|
24
|
+
showGridLines = true,
|
|
25
|
+
curveType = "monotone",
|
|
26
|
+
connectNulls = true,
|
|
27
|
+
categoryLabels
|
|
28
|
+
}) {
|
|
29
|
+
const getLineColor = (idx) => resolveChartColor(colors?.[idx], idx);
|
|
30
|
+
const ChartComponent = showArea ? RechartsAreaChart : RechartsLineChart;
|
|
31
|
+
return /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
|
|
32
|
+
ChartComponent,
|
|
33
|
+
{
|
|
34
|
+
data,
|
|
35
|
+
margin: { top: 5, right: 10, left: 10, bottom: 5 },
|
|
36
|
+
children: [
|
|
37
|
+
showGridLines && /* @__PURE__ */ jsx(
|
|
38
|
+
CartesianGrid,
|
|
39
|
+
{
|
|
40
|
+
strokeDasharray: "3 3",
|
|
41
|
+
stroke: "hsl(var(--border))"
|
|
42
|
+
}
|
|
43
|
+
),
|
|
44
|
+
/* @__PURE__ */ jsx(
|
|
45
|
+
XAxis,
|
|
46
|
+
{
|
|
47
|
+
dataKey: index,
|
|
48
|
+
tick: { fontSize: 12 },
|
|
49
|
+
tickLine: false,
|
|
50
|
+
axisLine: false
|
|
51
|
+
}
|
|
52
|
+
),
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
YAxis,
|
|
55
|
+
{
|
|
56
|
+
tickFormatter: valueFormatter,
|
|
57
|
+
tick: { fontSize: 12 },
|
|
58
|
+
tickLine: false,
|
|
59
|
+
axisLine: false,
|
|
60
|
+
width: 56
|
|
61
|
+
}
|
|
62
|
+
),
|
|
63
|
+
/* @__PURE__ */ jsx(
|
|
64
|
+
Tooltip,
|
|
65
|
+
{
|
|
66
|
+
content: /* @__PURE__ */ jsx(ChartTooltipContent, { valueFormatter, categoryLabels }),
|
|
67
|
+
cursor: { stroke: "hsl(var(--muted-foreground))", strokeDasharray: "3 3" }
|
|
68
|
+
}
|
|
69
|
+
),
|
|
70
|
+
showLegend && categories.length > 1 && /* @__PURE__ */ jsx(
|
|
71
|
+
Legend,
|
|
72
|
+
{
|
|
73
|
+
verticalAlign: "top",
|
|
74
|
+
height: 36,
|
|
75
|
+
formatter: (value) => /* @__PURE__ */ jsx("span", { style: { color: "hsl(var(--muted-foreground))", fontSize: "12px" }, children: value })
|
|
76
|
+
}
|
|
77
|
+
),
|
|
78
|
+
showArea ? categories.map((category, idx) => /* @__PURE__ */ jsx(
|
|
79
|
+
Area,
|
|
80
|
+
{
|
|
81
|
+
type: curveType,
|
|
82
|
+
dataKey: category,
|
|
83
|
+
stroke: getLineColor(idx),
|
|
84
|
+
fill: getLineColor(idx),
|
|
85
|
+
fillOpacity: 0.2,
|
|
86
|
+
strokeWidth: 2,
|
|
87
|
+
connectNulls,
|
|
88
|
+
dot: false,
|
|
89
|
+
activeDot: { r: 4, strokeWidth: 0 }
|
|
90
|
+
},
|
|
91
|
+
category
|
|
92
|
+
)) : categories.map((category, idx) => /* @__PURE__ */ jsx(
|
|
93
|
+
Line,
|
|
94
|
+
{
|
|
95
|
+
type: curveType,
|
|
96
|
+
dataKey: category,
|
|
97
|
+
stroke: getLineColor(idx),
|
|
98
|
+
strokeWidth: 2,
|
|
99
|
+
connectNulls,
|
|
100
|
+
dot: false,
|
|
101
|
+
activeDot: { r: 4, strokeWidth: 0 }
|
|
102
|
+
},
|
|
103
|
+
category
|
|
104
|
+
))
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
) });
|
|
108
|
+
}
|
|
109
|
+
export {
|
|
110
|
+
LineChartImpl as default
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=LineChartImpl.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/backend/charts/LineChartImpl.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {\n LineChart as RechartsLineChart,\n AreaChart as RechartsAreaChart,\n Line,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n Legend,\n} from 'recharts'\nimport { ChartTooltipContent, resolveChartColor } from './ChartUtils'\nimport type { LineChartProps } from './LineChart'\n\ntype ImplProps = Pick<\n LineChartProps,\n | 'data'\n | 'index'\n | 'categories'\n | 'colors'\n | 'showArea'\n | 'valueFormatter'\n | 'showLegend'\n | 'showGridLines'\n | 'curveType'\n | 'connectNulls'\n | 'categoryLabels'\n> & {\n valueFormatter: (value: number) => string\n}\n\nexport default function LineChartImpl({\n data,\n index,\n categories,\n colors,\n showArea = false,\n valueFormatter,\n showLegend = true,\n showGridLines = true,\n curveType = 'monotone',\n connectNulls = true,\n categoryLabels,\n}: ImplProps) {\n const getLineColor = (idx: number): string => resolveChartColor(colors?.[idx], idx)\n const ChartComponent = showArea ? RechartsAreaChart : RechartsLineChart\n\n return (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <ChartComponent\n data={data}\n margin={{ top: 5, right: 10, left: 10, bottom: 5 }}\n >\n {showGridLines && (\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"hsl(var(--border))\"\n />\n )}\n <XAxis\n dataKey={index}\n tick={{ fontSize: 12 }}\n tickLine={false}\n axisLine={false}\n />\n <YAxis\n tickFormatter={valueFormatter}\n tick={{ fontSize: 12 }}\n tickLine={false}\n axisLine={false}\n width={56}\n />\n <Tooltip\n content={<ChartTooltipContent valueFormatter={valueFormatter} categoryLabels={categoryLabels} />}\n cursor={{ stroke: 'hsl(var(--muted-foreground))', strokeDasharray: '3 3' }}\n />\n {showLegend && categories.length > 1 && (\n <Legend\n verticalAlign=\"top\"\n height={36}\n formatter={(value) => (\n <span style={{ color: 'hsl(var(--muted-foreground))', fontSize: '12px' }}>{value}</span>\n )}\n />\n )}\n {showArea\n ? categories.map((category, idx) => (\n <Area\n key={category}\n type={curveType}\n dataKey={category}\n stroke={getLineColor(idx)}\n fill={getLineColor(idx)}\n fillOpacity={0.2}\n strokeWidth={2}\n connectNulls={connectNulls}\n dot={false}\n activeDot={{ r: 4, strokeWidth: 0 }}\n />\n ))\n : categories.map((category, idx) => (\n <Line\n key={category}\n type={curveType}\n dataKey={category}\n stroke={getLineColor(idx)}\n strokeWidth={2}\n connectNulls={connectNulls}\n dot={false}\n activeDot={{ r: 4, strokeWidth: 0 }}\n />\n ))}\n </ChartComponent>\n </ResponsiveContainer>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAqDM,SAKI,KALJ;AAlDN;AAAA,EACE,aAAa;AAAA,EACb,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB,yBAAyB;AAoBxC,SAAR,cAA+B;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,eAAe;AAAA,EACf;AACF,GAAc;AACZ,QAAM,eAAe,CAAC,QAAwB,kBAAkB,SAAS,GAAG,GAAG,GAAG;AAClF,QAAM,iBAAiB,WAAW,oBAAoB;AAEtD,SACE,oBAAC,uBAAoB,OAAM,QAAO,QAAO,QACvC;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,QAAQ,EAAE,KAAK,GAAG,OAAO,IAAI,MAAM,IAAI,QAAQ,EAAE;AAAA,MAEhD;AAAA,yBACC;AAAA,UAAC;AAAA;AAAA,YACC,iBAAgB;AAAA,YAChB,QAAO;AAAA;AAAA,QACT;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,MAAM,EAAE,UAAU,GAAG;AAAA,YACrB,UAAU;AAAA,YACV,UAAU;AAAA;AAAA,QACZ;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,eAAe;AAAA,YACf,MAAM,EAAE,UAAU,GAAG;AAAA,YACrB,UAAU;AAAA,YACV,UAAU;AAAA,YACV,OAAO;AAAA;AAAA,QACT;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,oBAAC,uBAAoB,gBAAgC,gBAAgC;AAAA,YAC9F,QAAQ,EAAE,QAAQ,gCAAgC,iBAAiB,MAAM;AAAA;AAAA,QAC3E;AAAA,QACC,cAAc,WAAW,SAAS,KACjC;AAAA,UAAC;AAAA;AAAA,YACC,eAAc;AAAA,YACd,QAAQ;AAAA,YACR,WAAW,CAAC,UACV,oBAAC,UAAK,OAAO,EAAE,OAAO,gCAAgC,UAAU,OAAO,GAAI,iBAAM;AAAA;AAAA,QAErF;AAAA,QAED,WACG,WAAW,IAAI,CAAC,UAAU,QACxB;AAAA,UAAC;AAAA;AAAA,YAEC,MAAM;AAAA,YACN,SAAS;AAAA,YACT,QAAQ,aAAa,GAAG;AAAA,YACxB,MAAM,aAAa,GAAG;AAAA,YACtB,aAAa;AAAA,YACb,aAAa;AAAA,YACb;AAAA,YACA,KAAK;AAAA,YACL,WAAW,EAAE,GAAG,GAAG,aAAa,EAAE;AAAA;AAAA,UAT7B;AAAA,QAUP,CACD,IACD,WAAW,IAAI,CAAC,UAAU,QACxB;AAAA,UAAC;AAAA;AAAA,YAEC,MAAM;AAAA,YACN,SAAS;AAAA,YACT,QAAQ,aAAa,GAAG;AAAA,YACxB,aAAa;AAAA,YACb;AAAA,YACA,KAAK;AAAA,YACL,WAAW,EAAE,GAAG,GAAG,aAAa,EAAE;AAAA;AAAA,UAP7B;AAAA,QAQP,CACD;AAAA;AAAA;AAAA,EACP,GACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,17 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import
|
|
5
|
-
PieChart as RechartsPieChart,
|
|
6
|
-
Pie,
|
|
7
|
-
Cell,
|
|
8
|
-
Tooltip,
|
|
9
|
-
ResponsiveContainer,
|
|
10
|
-
Legend,
|
|
11
|
-
Label
|
|
12
|
-
} from "recharts";
|
|
4
|
+
import dynamic from "next/dynamic";
|
|
13
5
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
14
|
-
import { ChartTooltipContent, resolveChartColor } from "./ChartUtils.js";
|
|
15
6
|
function defaultValueFormatter(value) {
|
|
16
7
|
if (Math.abs(value) >= 1e6) {
|
|
17
8
|
return `${(value / 1e6).toFixed(1)}M`;
|
|
@@ -21,6 +12,10 @@ function defaultValueFormatter(value) {
|
|
|
21
12
|
}
|
|
22
13
|
return value.toLocaleString(void 0, { maximumFractionDigits: 2 });
|
|
23
14
|
}
|
|
15
|
+
const PieChartImpl = dynamic(() => import("./PieChartImpl.js"), {
|
|
16
|
+
ssr: false,
|
|
17
|
+
loading: () => /* @__PURE__ */ jsx("div", { className: "flex h-48 items-center justify-center", children: /* @__PURE__ */ jsx(Spinner, { className: "h-6 w-6 text-muted-foreground" }) })
|
|
18
|
+
});
|
|
24
19
|
function PieChart({
|
|
25
20
|
title,
|
|
26
21
|
data,
|
|
@@ -34,9 +29,6 @@ function PieChart({
|
|
|
34
29
|
className = "",
|
|
35
30
|
emptyMessage = "No data available"
|
|
36
31
|
}) {
|
|
37
|
-
const getSliceColor = (idx) => {
|
|
38
|
-
return resolveChartColor(colors?.[idx], idx);
|
|
39
|
-
};
|
|
40
32
|
const total = React.useMemo(() => {
|
|
41
33
|
return data.reduce((sum, item) => sum + item.value, 0);
|
|
42
34
|
}, [data]);
|
|
@@ -60,57 +52,20 @@ function PieChart({
|
|
|
60
52
|
/* @__PURE__ */ jsx("div", { className: "flex h-48 items-center justify-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessage }) })
|
|
61
53
|
] });
|
|
62
54
|
}
|
|
63
|
-
const innerRadius = variant === "donut" ? "60%" : 0;
|
|
64
|
-
const outerRadius = "80%";
|
|
65
55
|
return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
|
|
66
56
|
title && /* @__PURE__ */ jsx("h3", { className: "mb-4 text-base font-medium text-card-foreground", children: title }),
|
|
67
|
-
/* @__PURE__ */ jsx("div", { className: "h-52 w-full", children: /* @__PURE__ */ jsx(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
strokeWidth: 0,
|
|
80
|
-
children: [
|
|
81
|
-
data.map((_, idx) => /* @__PURE__ */ jsx(Cell, { fill: getSliceColor(idx) }, `cell-${idx}`)),
|
|
82
|
-
showLabel && variant === "donut" && /* @__PURE__ */ jsx(
|
|
83
|
-
Label,
|
|
84
|
-
{
|
|
85
|
-
value: valueFormatter(total),
|
|
86
|
-
position: "center",
|
|
87
|
-
className: "fill-foreground text-2xl font-bold"
|
|
88
|
-
}
|
|
89
|
-
)
|
|
90
|
-
]
|
|
91
|
-
}
|
|
92
|
-
),
|
|
93
|
-
showTooltip && /* @__PURE__ */ jsx(
|
|
94
|
-
Tooltip,
|
|
95
|
-
{
|
|
96
|
-
content: /* @__PURE__ */ jsx(
|
|
97
|
-
ChartTooltipContent,
|
|
98
|
-
{
|
|
99
|
-
valueFormatter,
|
|
100
|
-
hideLabel: true
|
|
101
|
-
}
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
),
|
|
105
|
-
/* @__PURE__ */ jsx(
|
|
106
|
-
Legend,
|
|
107
|
-
{
|
|
108
|
-
verticalAlign: "bottom",
|
|
109
|
-
height: 36,
|
|
110
|
-
formatter: (value) => /* @__PURE__ */ jsx("span", { style: { color: "hsl(var(--muted-foreground))", fontSize: "12px" }, children: value })
|
|
111
|
-
}
|
|
112
|
-
)
|
|
113
|
-
] }) }) })
|
|
57
|
+
/* @__PURE__ */ jsx("div", { className: "h-52 w-full", children: /* @__PURE__ */ jsx(
|
|
58
|
+
PieChartImpl,
|
|
59
|
+
{
|
|
60
|
+
data,
|
|
61
|
+
colors,
|
|
62
|
+
variant,
|
|
63
|
+
valueFormatter,
|
|
64
|
+
showLabel,
|
|
65
|
+
showTooltip,
|
|
66
|
+
total
|
|
67
|
+
}
|
|
68
|
+
) })
|
|
114
69
|
] });
|
|
115
70
|
}
|
|
116
71
|
var PieChart_default = PieChart;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/charts/PieChart.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport dynamic from 'next/dynamic'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\n\nexport type PieChartDataItem = {\n name: string\n value: number\n}\n\nexport type PieChartProps = {\n title?: string\n data: PieChartDataItem[]\n loading?: boolean\n error?: string | null\n colors?: string[]\n variant?: 'pie' | 'donut'\n valueFormatter?: (value: number) => string\n showLabel?: boolean\n showTooltip?: boolean\n className?: string\n emptyMessage?: string\n}\n\nfunction defaultValueFormatter(value: number): string {\n if (Math.abs(value) >= 1_000_000) {\n return `${(value / 1_000_000).toFixed(1)}M`\n }\n if (Math.abs(value) >= 1_000) {\n return `${(value / 1_000).toFixed(1)}K`\n }\n return value.toLocaleString(undefined, { maximumFractionDigits: 2 })\n}\n\nconst PieChartImpl = dynamic(() => import('./PieChartImpl'), {\n ssr: false,\n loading: () => (\n <div className=\"flex h-48 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n ),\n})\n\nexport function PieChart({\n title,\n data,\n loading,\n error,\n colors,\n variant = 'donut',\n valueFormatter = defaultValueFormatter,\n showLabel = true,\n showTooltip = true,\n className = '',\n emptyMessage = 'No data available',\n}: PieChartProps) {\n const total = React.useMemo(() => {\n return data.reduce((sum, item) => sum + item.value, 0)\n }, [data])\n\n const hasWrapper = !!title\n const wrapperClass = hasWrapper ? `rounded-lg border bg-card p-4 ${className}` : className\n\n if (error) {\n return (\n <div className={wrapperClass}>\n {title && <h3 className=\"mb-4 text-base font-medium text-card-foreground\">{title}</h3>}\n <div className=\"flex h-48 items-center justify-center\">\n <p className=\"text-sm text-destructive\">{error}</p>\n </div>\n </div>\n )\n }\n\n if (loading) {\n return (\n <div className={wrapperClass}>\n {title && <h3 className=\"mb-4 text-base font-medium text-card-foreground\">{title}</h3>}\n <div className=\"flex h-48 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n </div>\n )\n }\n\n if (!data || data.length === 0) {\n return (\n <div className={wrapperClass}>\n {title && <h3 className=\"mb-4 text-base font-medium text-card-foreground\">{title}</h3>}\n <div className=\"flex h-48 items-center justify-center\">\n <p className=\"text-sm text-muted-foreground\">{emptyMessage}</p>\n </div>\n </div>\n )\n }\n\n return (\n <div className={wrapperClass}>\n {title && <h3 className=\"mb-4 text-base font-medium text-card-foreground\">{title}</h3>}\n <div className=\"h-52 w-full\">\n <PieChartImpl\n data={data}\n colors={colors}\n variant={variant}\n valueFormatter={valueFormatter}\n showLabel={showLabel}\n showTooltip={showTooltip}\n total={total}\n />\n </div>\n </div>\n )\n}\n\nexport default PieChart\n"],
|
|
5
|
+
"mappings": ";AAuCM,cA2BA,YA3BA;AArCN,YAAY,WAAW;AACvB,OAAO,aAAa;AACpB,SAAS,eAAe;AAqBxB,SAAS,sBAAsB,OAAuB;AACpD,MAAI,KAAK,IAAI,KAAK,KAAK,KAAW;AAChC,WAAO,IAAI,QAAQ,KAAW,QAAQ,CAAC,CAAC;AAAA,EAC1C;AACA,MAAI,KAAK,IAAI,KAAK,KAAK,KAAO;AAC5B,WAAO,IAAI,QAAQ,KAAO,QAAQ,CAAC,CAAC;AAAA,EACtC;AACA,SAAO,MAAM,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC;AACrE;AAEA,MAAM,eAAe,QAAQ,MAAM,OAAO,gBAAgB,GAAG;AAAA,EAC3D,KAAK;AAAA,EACL,SAAS,MACP,oBAAC,SAAI,WAAU,yCACb,8BAAC,WAAQ,WAAU,iCAAgC,GACrD;AAEJ,CAAC;AAEM,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,eAAe;AACjB,GAAkB;AAChB,QAAM,QAAQ,MAAM,QAAQ,MAAM;AAChC,WAAO,KAAK,OAAO,CAAC,KAAK,SAAS,MAAM,KAAK,OAAO,CAAC;AAAA,EACvD,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,aAAa,CAAC,CAAC;AACrB,QAAM,eAAe,aAAa,iCAAiC,SAAS,KAAK;AAEjF,MAAI,OAAO;AACT,WACE,qBAAC,SAAI,WAAW,cACb;AAAA,eAAS,oBAAC,QAAG,WAAU,mDAAmD,iBAAM;AAAA,MACjF,oBAAC,SAAI,WAAU,yCACb,8BAAC,OAAE,WAAU,4BAA4B,iBAAM,GACjD;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,qBAAC,SAAI,WAAW,cACb;AAAA,eAAS,oBAAC,QAAG,WAAU,mDAAmD,iBAAM;AAAA,MACjF,oBAAC,SAAI,WAAU,yCACb,8BAAC,WAAQ,WAAU,iCAAgC,GACrD;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAC9B,WACE,qBAAC,SAAI,WAAW,cACb;AAAA,eAAS,oBAAC,QAAG,WAAU,mDAAmD,iBAAM;AAAA,MACjF,oBAAC,SAAI,WAAU,yCACb,8BAAC,OAAE,WAAU,iCAAiC,wBAAa,GAC7D;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAW,cACb;AAAA,aAAS,oBAAC,QAAG,WAAU,mDAAmD,iBAAM;AAAA,IACjF,oBAAC,SAAI,WAAU,eACb;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;AAEA,IAAO,mBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import {
|
|
4
|
+
PieChart as RechartsPieChart,
|
|
5
|
+
Pie,
|
|
6
|
+
Cell,
|
|
7
|
+
Tooltip,
|
|
8
|
+
ResponsiveContainer,
|
|
9
|
+
Legend,
|
|
10
|
+
Label
|
|
11
|
+
} from "recharts";
|
|
12
|
+
import { ChartTooltipContent, resolveChartColor } from "./ChartUtils.js";
|
|
13
|
+
function PieChartImpl({
|
|
14
|
+
data,
|
|
15
|
+
colors,
|
|
16
|
+
variant = "donut",
|
|
17
|
+
valueFormatter,
|
|
18
|
+
showLabel = true,
|
|
19
|
+
showTooltip = true,
|
|
20
|
+
total
|
|
21
|
+
}) {
|
|
22
|
+
const getSliceColor = (idx) => resolveChartColor(colors?.[idx], idx);
|
|
23
|
+
const innerRadius = variant === "donut" ? "60%" : 0;
|
|
24
|
+
const outerRadius = "80%";
|
|
25
|
+
return /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(RechartsPieChart, { children: [
|
|
26
|
+
/* @__PURE__ */ jsxs(
|
|
27
|
+
Pie,
|
|
28
|
+
{
|
|
29
|
+
data,
|
|
30
|
+
dataKey: "value",
|
|
31
|
+
nameKey: "name",
|
|
32
|
+
cx: "50%",
|
|
33
|
+
cy: "40%",
|
|
34
|
+
innerRadius,
|
|
35
|
+
outerRadius,
|
|
36
|
+
paddingAngle: 2,
|
|
37
|
+
strokeWidth: 0,
|
|
38
|
+
children: [
|
|
39
|
+
data.map((_, idx) => /* @__PURE__ */ jsx(Cell, { fill: getSliceColor(idx) }, `cell-${idx}`)),
|
|
40
|
+
showLabel && variant === "donut" && /* @__PURE__ */ jsx(
|
|
41
|
+
Label,
|
|
42
|
+
{
|
|
43
|
+
value: valueFormatter(total),
|
|
44
|
+
position: "center",
|
|
45
|
+
className: "fill-foreground text-2xl font-bold"
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
),
|
|
51
|
+
showTooltip && /* @__PURE__ */ jsx(
|
|
52
|
+
Tooltip,
|
|
53
|
+
{
|
|
54
|
+
content: /* @__PURE__ */ jsx(
|
|
55
|
+
ChartTooltipContent,
|
|
56
|
+
{
|
|
57
|
+
valueFormatter,
|
|
58
|
+
hideLabel: true
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
),
|
|
63
|
+
/* @__PURE__ */ jsx(
|
|
64
|
+
Legend,
|
|
65
|
+
{
|
|
66
|
+
verticalAlign: "bottom",
|
|
67
|
+
height: 36,
|
|
68
|
+
formatter: (value) => /* @__PURE__ */ jsx("span", { style: { color: "hsl(var(--muted-foreground))", fontSize: "12px" }, children: value })
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
] }) });
|
|
72
|
+
}
|
|
73
|
+
export {
|
|
74
|
+
PieChartImpl as default
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=PieChartImpl.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/backend/charts/PieChartImpl.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {\n PieChart as RechartsPieChart,\n Pie,\n Cell,\n Tooltip,\n ResponsiveContainer,\n Legend,\n Label,\n} from 'recharts'\nimport { ChartTooltipContent, resolveChartColor } from './ChartUtils'\nimport type { PieChartProps } from './PieChart'\n\ntype ImplProps = Pick<\n PieChartProps,\n 'data' | 'colors' | 'variant' | 'valueFormatter' | 'showLabel' | 'showTooltip'\n> & {\n valueFormatter: (value: number) => string\n total: number\n}\n\nexport default function PieChartImpl({\n data,\n colors,\n variant = 'donut',\n valueFormatter,\n showLabel = true,\n showTooltip = true,\n total,\n}: ImplProps) {\n const getSliceColor = (idx: number): string => resolveChartColor(colors?.[idx], idx)\n const innerRadius = variant === 'donut' ? '60%' : 0\n const outerRadius = '80%'\n\n return (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsPieChart>\n <Pie\n data={data}\n dataKey=\"value\"\n nameKey=\"name\"\n cx=\"50%\"\n cy=\"40%\"\n innerRadius={innerRadius}\n outerRadius={outerRadius}\n paddingAngle={2}\n strokeWidth={0}\n >\n {data.map((_, idx) => (\n <Cell key={`cell-${idx}`} fill={getSliceColor(idx)} />\n ))}\n {showLabel && variant === 'donut' && (\n <Label\n value={valueFormatter(total)}\n position=\"center\"\n className=\"fill-foreground text-2xl font-bold\"\n />\n )}\n </Pie>\n {showTooltip && (\n <Tooltip\n content={\n <ChartTooltipContent\n valueFormatter={valueFormatter}\n hideLabel\n />\n }\n />\n )}\n <Legend\n verticalAlign=\"bottom\"\n height={36}\n formatter={(value) => (\n <span style={{ color: 'hsl(var(--muted-foreground))', fontSize: '12px' }}>{value}</span>\n )}\n />\n </RechartsPieChart>\n </ResponsiveContainer>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAuCQ,SAYI,KAZJ;AApCR;AAAA,EACE,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB,yBAAyB;AAWxC,SAAR,aAA8B;AAAA,EACnC;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,YAAY;AAAA,EACZ,cAAc;AAAA,EACd;AACF,GAAc;AACZ,QAAM,gBAAgB,CAAC,QAAwB,kBAAkB,SAAS,GAAG,GAAG,GAAG;AACnF,QAAM,cAAc,YAAY,UAAU,QAAQ;AAClD,QAAM,cAAc;AAEpB,SACE,oBAAC,uBAAoB,OAAM,QAAO,QAAO,QACvC,+BAAC,oBACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,SAAQ;AAAA,QACR,SAAQ;AAAA,QACR,IAAG;AAAA,QACH,IAAG;AAAA,QACH;AAAA,QACA;AAAA,QACA,cAAc;AAAA,QACd,aAAa;AAAA,QAEZ;AAAA,eAAK,IAAI,CAAC,GAAG,QACZ,oBAAC,QAAyB,MAAM,cAAc,GAAG,KAAtC,QAAQ,GAAG,EAA8B,CACrD;AAAA,UACA,aAAa,YAAY,WACxB;AAAA,YAAC;AAAA;AAAA,cACC,OAAO,eAAe,KAAK;AAAA,cAC3B,UAAS;AAAA,cACT,WAAU;AAAA;AAAA,UACZ;AAAA;AAAA;AAAA,IAEJ;AAAA,IACC,eACC;AAAA,MAAC;AAAA;AAAA,QACC,SACE;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,WAAS;AAAA;AAAA,QACX;AAAA;AAAA,IAEJ;AAAA,IAEF;AAAA,MAAC;AAAA;AAAA,QACC,eAAc;AAAA,QACd,QAAQ;AAAA,QACR,WAAW,CAAC,UACV,oBAAC,UAAK,OAAO,EAAE,OAAO,gCAAgC,UAAU,OAAO,GAAI,iBAAM;AAAA;AAAA,IAErF;AAAA,KACF,GACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -11,6 +11,7 @@ import { getDashboardWidgets, loadDashboardWidgetModule } from "./widgetRegistry
|
|
|
11
11
|
import { cn } from "@open-mercato/shared/lib/utils";
|
|
12
12
|
import { GripVertical, Info, Plus, RefreshCw, Settings2, Trash2, X, Loader2 } from "lucide-react";
|
|
13
13
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
14
|
+
import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
|
|
14
15
|
import { InjectionSpot } from "../injection/InjectionSpot.js";
|
|
15
16
|
function sizeClass(size) {
|
|
16
17
|
switch (size) {
|
|
@@ -39,6 +40,7 @@ function generateId() {
|
|
|
39
40
|
}
|
|
40
41
|
function DashboardScreen() {
|
|
41
42
|
const t = useT();
|
|
43
|
+
const organizationScopeVersion = useOrganizationScopeVersion();
|
|
42
44
|
const [loading, setLoading] = React.useState(true);
|
|
43
45
|
const [error, setError] = React.useState(null);
|
|
44
46
|
const [hasRegisteredWidgets, setHasRegisteredWidgets] = React.useState(true);
|
|
@@ -109,7 +111,7 @@ function DashboardScreen() {
|
|
|
109
111
|
}, [t]);
|
|
110
112
|
React.useEffect(() => {
|
|
111
113
|
load();
|
|
112
|
-
}, [load]);
|
|
114
|
+
}, [load, organizationScopeVersion]);
|
|
113
115
|
const metaById = React.useMemo(() => {
|
|
114
116
|
const map = /* @__PURE__ */ new Map();
|
|
115
117
|
for (const meta of widgetCatalog) map.set(meta.id, meta);
|
|
@@ -450,6 +452,12 @@ function DashboardWidgetCard({
|
|
|
450
452
|
setLoadError(null);
|
|
451
453
|
loadDashboardWidgetModule(meta.loaderKey).then((loaded) => {
|
|
452
454
|
if (cancelled) return;
|
|
455
|
+
if (!loaded) {
|
|
456
|
+
setModule(null);
|
|
457
|
+
setLoadError(t("dashboard.widget.loadError"));
|
|
458
|
+
setLoading(false);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
453
461
|
setModule(loaded);
|
|
454
462
|
setLoading(false);
|
|
455
463
|
}).catch((err) => {
|