Fix/clean up order range dialog
This commit is contained in:
@@ -497,6 +497,24 @@ export class EventsService {
|
|||||||
dayStats.orderValueRange.smallest = totalAmount;
|
dayStats.orderValueRange.smallest = totalAmount;
|
||||||
dayStats.orderValueRange.smallestOrderId = orderId;
|
dayStats.orderValueRange.smallestOrderId = orderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track order value distribution
|
||||||
|
if (totalAmount < 25) {
|
||||||
|
dayStats.orderValueRange.distribution.under25.count++;
|
||||||
|
dayStats.orderValueRange.distribution.under25.total += totalAmount;
|
||||||
|
} else if (totalAmount < 50) {
|
||||||
|
dayStats.orderValueRange.distribution.under50.count++;
|
||||||
|
dayStats.orderValueRange.distribution.under50.total += totalAmount;
|
||||||
|
} else if (totalAmount < 100) {
|
||||||
|
dayStats.orderValueRange.distribution.under100.count++;
|
||||||
|
dayStats.orderValueRange.distribution.under100.total += totalAmount;
|
||||||
|
} else if (totalAmount < 200) {
|
||||||
|
dayStats.orderValueRange.distribution.under200.count++;
|
||||||
|
dayStats.orderValueRange.distribution.under200.total += totalAmount;
|
||||||
|
} else {
|
||||||
|
dayStats.orderValueRange.distribution.over200.count++;
|
||||||
|
dayStats.orderValueRange.distribution.over200.total += totalAmount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track order types
|
// Track order types
|
||||||
@@ -1256,24 +1274,37 @@ export class EventsService {
|
|||||||
|
|
||||||
const results = await Promise.all(eventPromises);
|
const results = await Promise.all(eventPromises);
|
||||||
|
|
||||||
// Combine and sort all events
|
// Transform and flatten the events into a single array
|
||||||
const allEvents = results
|
const allEvents = [];
|
||||||
.flatMap(result => result.data || [])
|
metrics.forEach((metric, index) => {
|
||||||
.sort((a, b) => new Date(b.attributes?.datetime) - new Date(a.attributes?.datetime));
|
const response = results[index];
|
||||||
|
const events = response?.data || [];
|
||||||
// Transform the events
|
if (Array.isArray(events)) {
|
||||||
const transformedEvents = this._transformEvents(allEvents);
|
const transformedEvents = events.map(event => ({
|
||||||
|
...event,
|
||||||
const result = {
|
metric_id: metric,
|
||||||
data: transformedEvents,
|
datetime: event.attributes?.datetime || event.datetime,
|
||||||
meta: {
|
event_properties: {
|
||||||
total_count: transformedEvents.length
|
...event.event_properties,
|
||||||
|
datetime: event.attributes?.datetime || event.datetime,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
allEvents.push(...transformedEvents);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// Cache the results
|
// Sort all events by datetime in descending order
|
||||||
|
allEvents.sort((a, b) => {
|
||||||
|
const dateA = new Date(a.datetime);
|
||||||
|
const dateB = new Date(b.datetime);
|
||||||
|
return dateB - dateA;
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = { data: allEvents };
|
||||||
|
|
||||||
|
// Cache the result
|
||||||
try {
|
try {
|
||||||
const ttl = this.redisService._getTTL(timeRange);
|
const ttl = this.redisService._getTTL(params.timeRange);
|
||||||
await this.redisService.set(`${cacheKey}:feed`, result, ttl);
|
await this.redisService.set(`${cacheKey}:feed`, result, ttl);
|
||||||
} catch (cacheError) {
|
} catch (cacheError) {
|
||||||
console.warn('[EventsService] Cache set error:', cacheError);
|
console.warn('[EventsService] Cache set error:', cacheError);
|
||||||
@@ -1281,7 +1312,7 @@ export class EventsService {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[EventsService] Error fetching multi-metric events:', error);
|
console.error('[EventsService] Error in batch metrics:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1481,26 +1512,21 @@ export class EventsService {
|
|||||||
const { metric, daily = false } = params;
|
const { metric, daily = false } = params;
|
||||||
console.log('[EventsService] Request params:', params);
|
console.log('[EventsService] Request params:', params);
|
||||||
|
|
||||||
// Get period dates
|
// Get period dates using the same logic as calculatePeriodStats
|
||||||
let periodStart, periodEnd, prevPeriodStart, prevPeriodEnd;
|
let periodStart, periodEnd, prevPeriodStart, prevPeriodEnd;
|
||||||
if (params.startDate && params.endDate) {
|
if (params.startDate && params.endDate) {
|
||||||
periodStart = this.timeManager.toDateTime(params.startDate);
|
periodStart = this.timeManager.toDateTime(params.startDate);
|
||||||
periodEnd = this.timeManager.toDateTime(params.endDate);
|
periodEnd = this.timeManager.toDateTime(params.endDate);
|
||||||
const duration = periodEnd.diff(periodStart);
|
const duration = periodEnd.diff(periodStart);
|
||||||
|
prevPeriodStart = periodStart.minus(duration);
|
||||||
prevPeriodEnd = periodStart.minus({ milliseconds: 1 });
|
prevPeriodEnd = periodStart.minus({ milliseconds: 1 });
|
||||||
prevPeriodStart = prevPeriodEnd.minus(duration);
|
|
||||||
} else if (params.timeRange) {
|
} else if (params.timeRange) {
|
||||||
const range = this.timeManager.getDateRange(params.timeRange);
|
const range = this.timeManager.getDateRange(params.timeRange);
|
||||||
const prevRange = this.timeManager.getPreviousPeriod(params.timeRange);
|
|
||||||
|
|
||||||
if (!range || !prevRange) {
|
|
||||||
throw new Error(`Invalid time range specified: ${params.timeRange}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
periodStart = range.start;
|
periodStart = range.start;
|
||||||
periodEnd = range.end;
|
periodEnd = range.end;
|
||||||
prevPeriodStart = prevRange.start;
|
const duration = periodEnd.diff(periodStart);
|
||||||
prevPeriodEnd = prevRange.end;
|
prevPeriodStart = periodStart.minus(duration);
|
||||||
|
prevPeriodEnd = periodStart.minus({ milliseconds: 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load both current and previous period data
|
// Load both current and previous period data
|
||||||
@@ -1572,7 +1598,20 @@ export class EventsService {
|
|||||||
prevRevenue: 0,
|
prevRevenue: 0,
|
||||||
prevOrders: 0,
|
prevOrders: 0,
|
||||||
prevItemCount: 0,
|
prevItemCount: 0,
|
||||||
prevAvgOrderValue: 0
|
prevAvgOrderValue: 0,
|
||||||
|
orderValueRange: {
|
||||||
|
largest: 0,
|
||||||
|
smallest: 0,
|
||||||
|
largestOrderId: null,
|
||||||
|
smallestOrderId: null,
|
||||||
|
distribution: {
|
||||||
|
under25: { count: 0, total: 0 },
|
||||||
|
under50: { count: 0, total: 0 },
|
||||||
|
under100: { count: 0, total: 0 },
|
||||||
|
under200: { count: 0, total: 0 },
|
||||||
|
over200: { count: 0, total: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
currentDate = currentDate.plus({ days: 1 });
|
currentDate = currentDate.plus({ days: 1 });
|
||||||
}
|
}
|
||||||
@@ -1592,6 +1631,7 @@ export class EventsService {
|
|||||||
const props = event.event_properties || {};
|
const props = event.event_properties || {};
|
||||||
const totalAmount = Number(props.TotalAmount || 0);
|
const totalAmount = Number(props.TotalAmount || 0);
|
||||||
const items = props.Items || [];
|
const items = props.Items || [];
|
||||||
|
const orderId = props.OrderId;
|
||||||
|
|
||||||
dayStats.revenue += totalAmount;
|
dayStats.revenue += totalAmount;
|
||||||
dayStats.orders++;
|
dayStats.orders++;
|
||||||
@@ -1602,6 +1642,36 @@ export class EventsService {
|
|||||||
dayStats.percentage = (dayStats.count / totalOrders) * 100;
|
dayStats.percentage = (dayStats.count / totalOrders) * 100;
|
||||||
dayStats.averageOrderValue = dayStats.revenue / dayStats.orders;
|
dayStats.averageOrderValue = dayStats.revenue / dayStats.orders;
|
||||||
dayStats.averageItemsPerOrder = dayStats.itemCount / dayStats.orders;
|
dayStats.averageItemsPerOrder = dayStats.itemCount / dayStats.orders;
|
||||||
|
|
||||||
|
// Track daily order value range
|
||||||
|
if (totalAmount > dayStats.orderValueRange.largest) {
|
||||||
|
dayStats.orderValueRange.largest = totalAmount;
|
||||||
|
dayStats.orderValueRange.largestOrderId = orderId;
|
||||||
|
}
|
||||||
|
if (totalAmount > 0) {
|
||||||
|
if (dayStats.orderValueRange.smallest === 0 || totalAmount < dayStats.orderValueRange.smallest) {
|
||||||
|
dayStats.orderValueRange.smallest = totalAmount;
|
||||||
|
dayStats.orderValueRange.smallestOrderId = orderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track order value distribution
|
||||||
|
if (totalAmount < 25) {
|
||||||
|
dayStats.orderValueRange.distribution.under25.count++;
|
||||||
|
dayStats.orderValueRange.distribution.under25.total += totalAmount;
|
||||||
|
} else if (totalAmount < 50) {
|
||||||
|
dayStats.orderValueRange.distribution.under50.count++;
|
||||||
|
dayStats.orderValueRange.distribution.under50.total += totalAmount;
|
||||||
|
} else if (totalAmount < 100) {
|
||||||
|
dayStats.orderValueRange.distribution.under100.count++;
|
||||||
|
dayStats.orderValueRange.distribution.under100.total += totalAmount;
|
||||||
|
} else if (totalAmount < 200) {
|
||||||
|
dayStats.orderValueRange.distribution.under200.count++;
|
||||||
|
dayStats.orderValueRange.distribution.under200.total += totalAmount;
|
||||||
|
} else {
|
||||||
|
dayStats.orderValueRange.distribution.over200.count++;
|
||||||
|
dayStats.orderValueRange.distribution.over200.total += totalAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process previous period events
|
// Process previous period events
|
||||||
@@ -1689,7 +1759,35 @@ export class EventsService {
|
|||||||
prevValue: Number(day.prevValue || 0),
|
prevValue: Number(day.prevValue || 0),
|
||||||
prevCount: Number(day.prevCount || 0),
|
prevCount: Number(day.prevCount || 0),
|
||||||
prevPercentage: Number(day.prevPercentage || 0),
|
prevPercentage: Number(day.prevPercentage || 0),
|
||||||
prevAvgOrderValue: Number(day.prevAvgOrderValue || 0)
|
prevAvgOrderValue: Number(day.prevAvgOrderValue || 0),
|
||||||
|
orderValueRange: {
|
||||||
|
largest: Number(day.orderValueRange?.largest || 0),
|
||||||
|
smallest: Number(day.orderValueRange?.smallest || 0),
|
||||||
|
largestOrderId: day.orderValueRange?.largestOrderId || null,
|
||||||
|
smallestOrderId: day.orderValueRange?.smallestOrderId || null,
|
||||||
|
distribution: {
|
||||||
|
under25: {
|
||||||
|
count: Number(day.orderValueRange?.distribution?.under25?.count || 0),
|
||||||
|
total: Number(day.orderValueRange?.distribution?.under25?.total || 0)
|
||||||
|
},
|
||||||
|
under50: {
|
||||||
|
count: Number(day.orderValueRange?.distribution?.under50?.count || 0),
|
||||||
|
total: Number(day.orderValueRange?.distribution?.under50?.total || 0)
|
||||||
|
},
|
||||||
|
under100: {
|
||||||
|
count: Number(day.orderValueRange?.distribution?.under100?.count || 0),
|
||||||
|
total: Number(day.orderValueRange?.distribution?.under100?.total || 0)
|
||||||
|
},
|
||||||
|
under200: {
|
||||||
|
count: Number(day.orderValueRange?.distribution?.under200?.count || 0),
|
||||||
|
total: Number(day.orderValueRange?.distribution?.under200?.total || 0)
|
||||||
|
},
|
||||||
|
over200: {
|
||||||
|
count: Number(day.orderValueRange?.distribution?.over200?.count || 0),
|
||||||
|
total: Number(day.orderValueRange?.distribution?.over200?.total || 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return stats;
|
return stats;
|
||||||
|
|||||||
@@ -105,6 +105,11 @@ const TimeSeriesChart = ({
|
|||||||
const ChartComponent = type === "line" ? LineChart : BarChart;
|
const ChartComponent = type === "line" ? LineChart : BarChart;
|
||||||
const DataComponent = type === "line" ? Line : Bar;
|
const DataComponent = type === "line" ? Line : Bar;
|
||||||
|
|
||||||
|
// Handle multiple series
|
||||||
|
const keys = Array.isArray(dataKey) ? dataKey : [dataKey];
|
||||||
|
const names = Array.isArray(name) ? name : [name];
|
||||||
|
const colors = Array.isArray(color) ? color : [color];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-[400px] w-full">
|
<div className="h-[400px] w-full">
|
||||||
<ResponsiveContainer width="100%" height={height}>
|
<ResponsiveContainer width="100%" height={height}>
|
||||||
@@ -135,15 +140,18 @@ const TimeSeriesChart = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Legend />
|
<Legend />
|
||||||
<DataComponent
|
{keys.map((key, index) => (
|
||||||
type="monotone"
|
<DataComponent
|
||||||
dataKey={dataKey}
|
key={key}
|
||||||
name={name}
|
type="monotone"
|
||||||
stroke={color}
|
dataKey={key}
|
||||||
fill={color}
|
name={names[index] || key}
|
||||||
strokeWidth={2}
|
stroke={colors[index]}
|
||||||
dot={false}
|
fill={colors[index]}
|
||||||
/>
|
strokeWidth={2}
|
||||||
|
dot={false}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</ChartComponent>
|
</ChartComponent>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
</div>
|
</div>
|
||||||
@@ -732,20 +740,6 @@ const RefundDetails = ({ data }) => {
|
|||||||
const OrderRangeDetails = ({ data }) => {
|
const OrderRangeDetails = ({ data }) => {
|
||||||
if (!data?.length) return <div className="text-muted-foreground">No data available for the selected time range.</div>;
|
if (!data?.length) return <div className="text-muted-foreground">No data available for the selected time range.</div>;
|
||||||
|
|
||||||
const rangeData = data[0]?.orderValueRange || {
|
|
||||||
largest: 0,
|
|
||||||
smallest: 0,
|
|
||||||
largestOrderId: null,
|
|
||||||
smallestOrderId: null,
|
|
||||||
distribution: {
|
|
||||||
under25: { count: 0, total: 0 },
|
|
||||||
under50: { count: 0, total: 0 },
|
|
||||||
under100: { count: 0, total: 0 },
|
|
||||||
under200: { count: 0, total: 0 },
|
|
||||||
over200: { count: 0, total: 0 }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const timeSeriesData = data.map(day => ({
|
const timeSeriesData = data.map(day => ({
|
||||||
timestamp: day.timestamp,
|
timestamp: day.timestamp,
|
||||||
largest: day.orderValueRange?.largest || 0,
|
largest: day.orderValueRange?.largest || 0,
|
||||||
@@ -753,116 +747,31 @@ const OrderRangeDetails = ({ data }) => {
|
|||||||
average: day.averageOrderValue || 0
|
average: day.averageOrderValue || 0
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const distributionData = [
|
|
||||||
{ range: 'Under $25', ...rangeData.distribution.under25 },
|
|
||||||
{ range: '$25-$50', ...rangeData.distribution.under50 },
|
|
||||||
{ range: '$50-$100', ...rangeData.distribution.under100 },
|
|
||||||
{ range: '$100-$200', ...rangeData.distribution.under200 },
|
|
||||||
{ range: 'Over $200', ...rangeData.distribution.over200 }
|
|
||||||
];
|
|
||||||
|
|
||||||
const totalOrders = distributionData.reduce((sum, range) => sum + (range.count || 0), 0);
|
|
||||||
const totalRevenue = distributionData.reduce((sum, range) => sum + (range.total || 0), 0);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<StatCard
|
|
||||||
title="Largest Order"
|
|
||||||
value={formatCurrency(rangeData.largest)}
|
|
||||||
description={rangeData.largestOrderId ? `Order #${rangeData.largestOrderId}` : null}
|
|
||||||
colorClass="text-violet-600 dark:text-violet-400"
|
|
||||||
icon={TrendingUp}
|
|
||||||
/>
|
|
||||||
<StatCard
|
|
||||||
title="Smallest Order"
|
|
||||||
value={formatCurrency(rangeData.smallest)}
|
|
||||||
description={rangeData.smallestOrderId ? `Order #${rangeData.smallestOrderId}` : null}
|
|
||||||
colorClass="text-violet-600 dark:text-violet-400"
|
|
||||||
icon={TrendingDown}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-medium mb-4">Order Value Range Over Time</h3>
|
<h3 className="text-lg font-medium mb-4">Order Value Range</h3>
|
||||||
<TimeSeriesChart
|
<TimeSeriesChart
|
||||||
data={timeSeriesData}
|
data={timeSeriesData}
|
||||||
dataKey="largest"
|
dataKey={["largest", "smallest"]}
|
||||||
name="Largest Order"
|
name={["Largest Order", "Smallest Order"]}
|
||||||
color="hsl(262.1 83.3% 57.8%)"
|
color={["hsl(262.1 83.3% 57.8%)", "hsl(221.2 83.2% 53.3%)"]}
|
||||||
valueFormatter={(value) => formatCurrency(value)}
|
valueFormatter={(value) => formatCurrency(value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-medium mb-4">Average Order Value Trend</h3>
|
<h3 className="text-lg font-medium mb-4">Average Order Value</h3>
|
||||||
<TimeSeriesChart
|
<TimeSeriesChart
|
||||||
data={timeSeriesData}
|
data={timeSeriesData}
|
||||||
dataKey="average"
|
dataKey="average"
|
||||||
name="Average Order Value"
|
name="Average Order Value"
|
||||||
color="hsl(221.2 83.2% 53.3%)"
|
color="hsl(142.1 76.2% 36.3%)"
|
||||||
valueFormatter={(value) => formatCurrency(value)}
|
valueFormatter={(value) => formatCurrency(value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<h3 className="text-lg font-medium mb-4">Order Value Distribution</h3>
|
|
||||||
<div className="grid grid-cols-2 gap-4 mb-4">
|
|
||||||
<StatCard
|
|
||||||
title="Total Orders"
|
|
||||||
value={totalOrders.toLocaleString()}
|
|
||||||
description="orders analyzed"
|
|
||||||
colorClass="text-violet-600 dark:text-violet-400"
|
|
||||||
icon={ShoppingCart}
|
|
||||||
/>
|
|
||||||
<StatCard
|
|
||||||
title="Total Revenue"
|
|
||||||
value={formatCurrency(totalRevenue)}
|
|
||||||
description="from all orders"
|
|
||||||
colorClass="text-violet-600 dark:text-violet-400"
|
|
||||||
icon={DollarSign}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="rounded-lg border bg-card">
|
|
||||||
<Table>
|
|
||||||
<TableHeader>
|
|
||||||
<TableRow>
|
|
||||||
<TableHead>Range</TableHead>
|
|
||||||
<TableHead className="text-right">Orders</TableHead>
|
|
||||||
<TableHead className="text-right">Total Revenue</TableHead>
|
|
||||||
<TableHead className="text-right">% of Orders</TableHead>
|
|
||||||
<TableHead className="text-right">Avg. Order Value</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{distributionData.map((range, index) => (
|
|
||||||
<TableRow key={index}>
|
|
||||||
<TableCell className="font-medium">{range.range}</TableCell>
|
|
||||||
<TableCell className="text-right">{range.count?.toLocaleString() || 0}</TableCell>
|
|
||||||
<TableCell className="text-right">{formatCurrency(range.total || 0)}</TableCell>
|
|
||||||
<TableCell className="text-right">
|
|
||||||
{((range.count / totalOrders) * 100).toFixed(1)}%
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-right">
|
|
||||||
{formatCurrency((range.total || 0) / (range.count || 1))}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h3 className="text-lg font-medium mb-4">Distribution Chart</h3>
|
|
||||||
<TimeSeriesChart
|
|
||||||
data={distributionData}
|
|
||||||
dataKey="count"
|
|
||||||
name="Orders"
|
|
||||||
type="bar"
|
|
||||||
color="hsl(262.1 83.3% 57.8%)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -1143,20 +1052,14 @@ const StatCards = ({
|
|||||||
|
|
||||||
// For order range
|
// For order range
|
||||||
if (metric === 'order_range') {
|
if (metric === 'order_range') {
|
||||||
const response = await axios.get('/api/klaviyo/events/stats/details', { params });
|
const response = await axios.get('/api/klaviyo/events/stats/details', {
|
||||||
const data = response.data.stats.map(day => ({
|
params: {
|
||||||
...day,
|
...params,
|
||||||
orderValueRange: {
|
eventType: 'PLACED_ORDER'
|
||||||
...day.orderValueRange,
|
|
||||||
distribution: day.orderValueRange?.distribution || {
|
|
||||||
under25: { count: 0, total: 0 },
|
|
||||||
under50: { count: 0, total: 0 },
|
|
||||||
under100: { count: 0, total: 0 },
|
|
||||||
under200: { count: 0, total: 0 },
|
|
||||||
over200: { count: 0, total: 0 }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
|
const data = response.data.stats;
|
||||||
|
console.log('Fetched order range data:', data);
|
||||||
setCacheData(detailTimeRange, metric, data);
|
setCacheData(detailTimeRange, metric, data);
|
||||||
setDetailData(prev => ({ ...prev, [metric]: data }));
|
setDetailData(prev => ({ ...prev, [metric]: data }));
|
||||||
setError(null);
|
setError(null);
|
||||||
@@ -1193,8 +1096,9 @@ const StatCards = ({
|
|||||||
'on_hold'
|
'on_hold'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Await all fetchDetailData calls
|
return Promise.all(
|
||||||
return Promise.all(metrics.map(metric => fetchDetailData(metric, metric))).catch(error => {
|
metrics.map(metric => fetchDetailData(metric, metric))
|
||||||
|
).catch(error => {
|
||||||
console.error('Error during detail data preload:', error);
|
console.error('Error during detail data preload:', error);
|
||||||
});
|
});
|
||||||
}, [fetchDetailData]);
|
}, [fetchDetailData]);
|
||||||
|
|||||||
Reference in New Issue
Block a user