@stoker-platform/web-app 0.5.189 → 0.5.191
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/CHANGELOG.md +15 -0
- package/package.json +4 -4
- package/src/DashboardChart.tsx +40 -5
- package/src/Form.tsx +19 -14
- package/src/List.tsx +14 -2
- package/src/components/ui/chart.tsx +15 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @stoker-platform/web-app
|
|
2
2
|
|
|
3
|
+
## 0.5.191
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- fix: fix image field upload spinner
|
|
8
|
+
|
|
9
|
+
## 0.5.190
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- feat: add chart currency option
|
|
14
|
+
- @stoker-platform/node-client@0.5.76
|
|
15
|
+
- @stoker-platform/utils@0.5.67
|
|
16
|
+
- @stoker-platform/web-client@0.5.78
|
|
17
|
+
|
|
3
18
|
## 0.5.189
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stoker-platform/web-app",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.191",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"scripts": {
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"@radix-ui/react-tooltip": "^1.2.8",
|
|
52
52
|
"@react-google-maps/api": "^2.20.8",
|
|
53
53
|
"@sentry/react": "^10.56.0",
|
|
54
|
-
"@stoker-platform/node-client": "0.5.
|
|
55
|
-
"@stoker-platform/utils": "0.5.
|
|
56
|
-
"@stoker-platform/web-client": "0.5.
|
|
54
|
+
"@stoker-platform/node-client": "0.5.76",
|
|
55
|
+
"@stoker-platform/utils": "0.5.67",
|
|
56
|
+
"@stoker-platform/web-client": "0.5.78",
|
|
57
57
|
"@tanstack/react-table": "^8.21.3",
|
|
58
58
|
"@types/react": "18.3.13",
|
|
59
59
|
"@types/react-dom": "18.3.1",
|
package/src/DashboardChart.tsx
CHANGED
|
@@ -140,8 +140,8 @@ export const DashboardChart = ({ chart, title, collection }: DashboardChartProps
|
|
|
140
140
|
const existingInterval = chartData.find((item) => item.date === date)
|
|
141
141
|
if (existingInterval) {
|
|
142
142
|
existingInterval.metric1 += metric1
|
|
143
|
-
if (
|
|
144
|
-
existingInterval.metric2
|
|
143
|
+
if (metric2) {
|
|
144
|
+
existingInterval.metric2 = (existingInterval.metric2 ?? 0) + metric2
|
|
145
145
|
}
|
|
146
146
|
} else {
|
|
147
147
|
chartData.push({ date, metric1, metric2 })
|
|
@@ -171,8 +171,8 @@ export const DashboardChart = ({ chart, title, collection }: DashboardChartProps
|
|
|
171
171
|
const existingInterval = chartData.find((item) => item.date === date)
|
|
172
172
|
if (existingInterval) {
|
|
173
173
|
existingInterval.metric1 += metric1
|
|
174
|
-
if (
|
|
175
|
-
existingInterval.metric2
|
|
174
|
+
if (metric2) {
|
|
175
|
+
existingInterval.metric2 = (existingInterval.metric2 ?? 0) + metric2
|
|
176
176
|
}
|
|
177
177
|
} else {
|
|
178
178
|
chartData.push({ date, metric1, metric2 })
|
|
@@ -246,6 +246,16 @@ export const DashboardChart = ({ chart, title, collection }: DashboardChartProps
|
|
|
246
246
|
metricField2?.name ||
|
|
247
247
|
"Total"
|
|
248
248
|
|
|
249
|
+
const hasMetric2 = !!(metricField2 || chart.formula2)
|
|
250
|
+
|
|
251
|
+
const currency = tryFunction(chart.currency)
|
|
252
|
+
const formatChartValue = (value: number) => {
|
|
253
|
+
if (currency) {
|
|
254
|
+
return `${currency}${value.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
|
|
255
|
+
}
|
|
256
|
+
return value.toLocaleString()
|
|
257
|
+
}
|
|
258
|
+
|
|
249
259
|
const chartConfig = {
|
|
250
260
|
visitors: {
|
|
251
261
|
label: metricTitle,
|
|
@@ -328,6 +338,31 @@ export const DashboardChart = ({ chart, title, collection }: DashboardChartProps
|
|
|
328
338
|
}
|
|
329
339
|
}}
|
|
330
340
|
indicator="dot"
|
|
341
|
+
valueFormatter={
|
|
342
|
+
currency
|
|
343
|
+
? (value) => formatChartValue(Number(value))
|
|
344
|
+
: undefined
|
|
345
|
+
}
|
|
346
|
+
footer={
|
|
347
|
+
hasMetric2
|
|
348
|
+
? (payload) => {
|
|
349
|
+
const total = payload.reduce(
|
|
350
|
+
(sum, item) => sum + (Number(item.value) || 0),
|
|
351
|
+
0,
|
|
352
|
+
)
|
|
353
|
+
return (
|
|
354
|
+
<div className="flex w-full justify-between gap-x-2 leading-none items-center">
|
|
355
|
+
<span className="text-muted-foreground">
|
|
356
|
+
Total
|
|
357
|
+
</span>
|
|
358
|
+
<span className="font-mono font-medium tabular-nums text-foreground">
|
|
359
|
+
{formatChartValue(total)}
|
|
360
|
+
</span>
|
|
361
|
+
</div>
|
|
362
|
+
)
|
|
363
|
+
}
|
|
364
|
+
: undefined
|
|
365
|
+
}
|
|
331
366
|
/>
|
|
332
367
|
}
|
|
333
368
|
/>
|
|
@@ -339,7 +374,7 @@ export const DashboardChart = ({ chart, title, collection }: DashboardChartProps
|
|
|
339
374
|
stackId="a"
|
|
340
375
|
isAnimationActive={chart.animate ?? true}
|
|
341
376
|
/>
|
|
342
|
-
{
|
|
377
|
+
{hasMetric2 && (
|
|
343
378
|
<Area
|
|
344
379
|
dataKey="metric2"
|
|
345
380
|
type="natural"
|
package/src/Form.tsx
CHANGED
|
@@ -2714,7 +2714,7 @@ function RecordForm({
|
|
|
2714
2714
|
async (
|
|
2715
2715
|
selectedPermissions: FilePermissions,
|
|
2716
2716
|
contextOverride?: "files" | "image-create" | "image-update",
|
|
2717
|
-
imageUpdateOverrides?: { pendingImage: { fieldName: string; file: File }; resolver
|
|
2717
|
+
imageUpdateOverrides?: { pendingImage: { fieldName: string; file: File }; resolver?: () => void },
|
|
2718
2718
|
) => {
|
|
2719
2719
|
const context = contextOverride ?? permissionsContext
|
|
2720
2720
|
if (context === "files") {
|
|
@@ -2840,6 +2840,10 @@ function RecordForm({
|
|
|
2840
2840
|
description: `Failed to upload ${filename}`,
|
|
2841
2841
|
variant: "destructive",
|
|
2842
2842
|
})
|
|
2843
|
+
resolve()
|
|
2844
|
+
if (effectiveResolver) {
|
|
2845
|
+
effectiveResolver()
|
|
2846
|
+
}
|
|
2843
2847
|
},
|
|
2844
2848
|
async () => {
|
|
2845
2849
|
try {
|
|
@@ -2912,20 +2916,21 @@ function RecordForm({
|
|
|
2912
2916
|
|
|
2913
2917
|
const uploadImageForUpdate = useCallback(
|
|
2914
2918
|
async (fieldName: string, file: File) => {
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2919
|
+
setPermissionsContext("image-update")
|
|
2920
|
+
setPendingImageForUpdate({ fieldName, file })
|
|
2921
|
+
setEditingFilename(file.name)
|
|
2922
|
+
setIsMultipleFileUpload(false)
|
|
2923
|
+
|
|
2924
|
+
if (shouldSkipPermissionsDialog()) {
|
|
2925
|
+
await handlePermissionsConfirm(getDefaultPermissions(), "image-update", {
|
|
2926
|
+
pendingImage: { fieldName, file },
|
|
2927
|
+
})
|
|
2928
|
+
return
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
await new Promise<void>((resolve) => {
|
|
2920
2932
|
setImageUpdateResolver(() => resolve)
|
|
2921
|
-
|
|
2922
|
-
handlePermissionsConfirm(getDefaultPermissions(), "image-update", {
|
|
2923
|
-
pendingImage: { fieldName, file },
|
|
2924
|
-
resolver: resolve,
|
|
2925
|
-
})
|
|
2926
|
-
} else {
|
|
2927
|
-
setShowPermissionsDialog(true)
|
|
2928
|
-
}
|
|
2933
|
+
setShowPermissionsDialog(true)
|
|
2929
2934
|
})
|
|
2930
2935
|
},
|
|
2931
2936
|
[shouldSkipPermissionsDialog, getDefaultPermissions, handlePermissionsConfirm],
|
package/src/List.tsx
CHANGED
|
@@ -111,6 +111,7 @@ interface AreaMetricChartProps {
|
|
|
111
111
|
timezone: string
|
|
112
112
|
showMetric2: boolean
|
|
113
113
|
showLegend: boolean
|
|
114
|
+
currency?: string
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
const AreaMetricChart = ({
|
|
@@ -120,7 +121,14 @@ const AreaMetricChart = ({
|
|
|
120
121
|
timezone,
|
|
121
122
|
showMetric2,
|
|
122
123
|
showLegend,
|
|
124
|
+
currency,
|
|
123
125
|
}: AreaMetricChartProps) => {
|
|
126
|
+
const formatChartValue = (value: number) => {
|
|
127
|
+
if (currency) {
|
|
128
|
+
return `${currency}${value.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
|
|
129
|
+
}
|
|
130
|
+
return value.toLocaleString()
|
|
131
|
+
}
|
|
124
132
|
const filteredData = useMemo(() => {
|
|
125
133
|
return chartData?.filter((item) => {
|
|
126
134
|
const date = new Date(item.date)
|
|
@@ -177,6 +185,7 @@ const AreaMetricChart = ({
|
|
|
177
185
|
})
|
|
178
186
|
}}
|
|
179
187
|
indicator="dot"
|
|
188
|
+
valueFormatter={currency ? (value) => formatChartValue(Number(value)) : undefined}
|
|
180
189
|
/>
|
|
181
190
|
}
|
|
182
191
|
/>
|
|
@@ -1413,8 +1422,8 @@ export function List({
|
|
|
1413
1422
|
const existingInterval = chartData.find((item) => item.date === date)
|
|
1414
1423
|
if (existingInterval) {
|
|
1415
1424
|
existingInterval.metric1 += metric1
|
|
1416
|
-
if (
|
|
1417
|
-
existingInterval.metric2
|
|
1425
|
+
if (metric2) {
|
|
1426
|
+
existingInterval.metric2 = (existingInterval.metric2 ?? 0) + metric2
|
|
1418
1427
|
}
|
|
1419
1428
|
} else {
|
|
1420
1429
|
chartData.push({ date, metric1, metric2 })
|
|
@@ -1626,6 +1635,8 @@ export function List({
|
|
|
1626
1635
|
},
|
|
1627
1636
|
} satisfies ChartConfig
|
|
1628
1637
|
|
|
1638
|
+
const currency = tryFunction(metric.currency)
|
|
1639
|
+
|
|
1629
1640
|
return (
|
|
1630
1641
|
<div key={`metric-${index}`} className="grid gap-3 flex-1 min-w-0">
|
|
1631
1642
|
<Card className="pt-0 w-full" key={`metric-${index}`}>
|
|
@@ -1675,6 +1686,7 @@ export function List({
|
|
|
1675
1686
|
timezone={timezone}
|
|
1676
1687
|
showMetric2={!!metricField2}
|
|
1677
1688
|
showLegend={!!(metricField1 && metricField2)}
|
|
1689
|
+
currency={currency}
|
|
1678
1690
|
/>
|
|
1679
1691
|
</CardContent>
|
|
1680
1692
|
</div>
|
|
@@ -89,6 +89,8 @@ ${colorConfig
|
|
|
89
89
|
|
|
90
90
|
const ChartTooltip = RechartsPrimitive.Tooltip
|
|
91
91
|
|
|
92
|
+
type ChartTooltipPayload = NonNullable<React.ComponentProps<typeof RechartsPrimitive.Tooltip>["payload"]>
|
|
93
|
+
|
|
92
94
|
const ChartTooltipContent = React.forwardRef<
|
|
93
95
|
HTMLDivElement,
|
|
94
96
|
React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
|
|
@@ -98,6 +100,8 @@ const ChartTooltipContent = React.forwardRef<
|
|
|
98
100
|
indicator?: "line" | "dot" | "dashed"
|
|
99
101
|
nameKey?: string
|
|
100
102
|
labelKey?: string
|
|
103
|
+
footer?: React.ReactNode | ((payload: ChartTooltipPayload) => React.ReactNode)
|
|
104
|
+
valueFormatter?: (value: number | string) => React.ReactNode
|
|
101
105
|
}
|
|
102
106
|
>(
|
|
103
107
|
(
|
|
@@ -115,6 +119,8 @@ const ChartTooltipContent = React.forwardRef<
|
|
|
115
119
|
color,
|
|
116
120
|
nameKey,
|
|
117
121
|
labelKey,
|
|
122
|
+
footer,
|
|
123
|
+
valueFormatter,
|
|
118
124
|
},
|
|
119
125
|
ref,
|
|
120
126
|
) => {
|
|
@@ -213,9 +219,11 @@ const ChartTooltipContent = React.forwardRef<
|
|
|
213
219
|
{itemConfig?.label || item.name}
|
|
214
220
|
</span>
|
|
215
221
|
</div>
|
|
216
|
-
{item.value && (
|
|
222
|
+
{item.value !== undefined && item.value !== null && (
|
|
217
223
|
<span className="font-mono font-medium tabular-nums text-foreground">
|
|
218
|
-
{
|
|
224
|
+
{valueFormatter
|
|
225
|
+
? valueFormatter(item.value as number | string)
|
|
226
|
+
: item.value.toLocaleString()}
|
|
219
227
|
</span>
|
|
220
228
|
)}
|
|
221
229
|
</div>
|
|
@@ -225,6 +233,11 @@ const ChartTooltipContent = React.forwardRef<
|
|
|
225
233
|
)
|
|
226
234
|
})}
|
|
227
235
|
</div>
|
|
236
|
+
{footer ? (
|
|
237
|
+
<div className="border-t border-border/50 pt-1.5">
|
|
238
|
+
{typeof footer === "function" ? footer(payload) : footer}
|
|
239
|
+
</div>
|
|
240
|
+
) : null}
|
|
228
241
|
</div>
|
|
229
242
|
)
|
|
230
243
|
},
|