Fix preorder/local/hold
This commit is contained in:
@@ -1512,21 +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 using the same logic as calculatePeriodStats
|
// Get period dates using TimeManager to respect 1 AM day start
|
||||||
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.getDayStart(this.timeManager.toDateTime(params.startDate));
|
||||||
periodEnd = this.timeManager.toDateTime(params.endDate);
|
periodEnd = this.timeManager.getDayEnd(this.timeManager.toDateTime(params.endDate));
|
||||||
const duration = periodEnd.diff(periodStart);
|
const duration = periodEnd.diff(periodStart);
|
||||||
prevPeriodStart = periodStart.minus(duration);
|
prevPeriodStart = this.timeManager.getDayStart(periodStart.minus(duration));
|
||||||
prevPeriodEnd = periodStart.minus({ milliseconds: 1 });
|
prevPeriodEnd = this.timeManager.getDayEnd(periodStart.minus({ milliseconds: 1 }));
|
||||||
} else if (params.timeRange) {
|
} else if (params.timeRange) {
|
||||||
const range = this.timeManager.getDateRange(params.timeRange);
|
const range = this.timeManager.getDateRange(params.timeRange);
|
||||||
periodStart = range.start;
|
periodStart = range.start;
|
||||||
periodEnd = range.end;
|
periodEnd = range.end;
|
||||||
const duration = periodEnd.diff(periodStart);
|
const prevRange = this.timeManager.getPreviousPeriod(params.timeRange);
|
||||||
prevPeriodStart = periodStart.minus(duration);
|
prevPeriodStart = prevRange.start;
|
||||||
prevPeriodEnd = periodStart.minus({ milliseconds: 1 });
|
prevPeriodEnd = prevRange.end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load both current and previous period data
|
// Load both current and previous period data
|
||||||
@@ -1549,36 +1549,7 @@ export class EventsService {
|
|||||||
const currentEvents = this._transformEvents(currentResponse.data || []);
|
const currentEvents = this._transformEvents(currentResponse.data || []);
|
||||||
const prevEvents = this._transformEvents(prevResponse.data || []);
|
const prevEvents = this._transformEvents(prevResponse.data || []);
|
||||||
|
|
||||||
// Filter events based on metric type
|
// Initialize daily stats map with all dates in range using TimeManager's day start
|
||||||
const filterEvents = (events) => {
|
|
||||||
switch (metric) {
|
|
||||||
case 'pre_orders':
|
|
||||||
return events.filter(event =>
|
|
||||||
Boolean(event.event_properties?.HasPreorder ||
|
|
||||||
event.event_properties?.has_preorder ||
|
|
||||||
event.event_properties?.preorder)
|
|
||||||
);
|
|
||||||
case 'local_pickup':
|
|
||||||
return events.filter(event =>
|
|
||||||
Boolean(event.event_properties?.LocalPickup ||
|
|
||||||
event.event_properties?.local_pickup ||
|
|
||||||
event.event_properties?.pickup)
|
|
||||||
);
|
|
||||||
case 'on_hold':
|
|
||||||
return events.filter(event =>
|
|
||||||
Boolean(event.event_properties?.IsOnHold ||
|
|
||||||
event.event_properties?.is_on_hold ||
|
|
||||||
event.event_properties?.on_hold)
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredCurrentEvents = filterEvents(currentEvents);
|
|
||||||
const filteredPrevEvents = filterEvents(prevEvents);
|
|
||||||
|
|
||||||
// Initialize daily stats map with all dates in range
|
|
||||||
const dailyStats = new Map();
|
const dailyStats = new Map();
|
||||||
let currentDate = periodStart;
|
let currentDate = periodStart;
|
||||||
while (currentDate <= periodEnd) {
|
while (currentDate <= periodEnd) {
|
||||||
@@ -1589,8 +1560,6 @@ export class EventsService {
|
|||||||
revenue: 0,
|
revenue: 0,
|
||||||
orders: 0,
|
orders: 0,
|
||||||
itemCount: 0,
|
itemCount: 0,
|
||||||
averageOrderValue: 0,
|
|
||||||
averageItemsPerOrder: 0,
|
|
||||||
count: 0,
|
count: 0,
|
||||||
value: 0,
|
value: 0,
|
||||||
percentage: 0,
|
percentage: 0,
|
||||||
@@ -1598,98 +1567,73 @@ export class EventsService {
|
|||||||
prevRevenue: 0,
|
prevRevenue: 0,
|
||||||
prevOrders: 0,
|
prevOrders: 0,
|
||||||
prevItemCount: 0,
|
prevItemCount: 0,
|
||||||
prevAvgOrderValue: 0,
|
prevValue: 0,
|
||||||
orderValueRange: {
|
prevCount: 0,
|
||||||
largest: 0,
|
prevPercentage: 0,
|
||||||
smallest: 0,
|
averageOrderValue: 0,
|
||||||
largestOrderId: null,
|
averageItemsPerOrder: 0,
|
||||||
smallestOrderId: null,
|
prevAvgOrderValue: 0
|
||||||
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 = this.timeManager.getDayStart(currentDate.plus({ days: 1 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get total orders for the period (needed for percentages)
|
// First pass: Count total orders per day using TimeManager's day boundaries
|
||||||
const totalOrders = currentEvents.length;
|
for (const event of currentEvents) {
|
||||||
|
const datetime = this.timeManager.toDateTime(event.attributes?.datetime);
|
||||||
|
if (!datetime) continue;
|
||||||
|
|
||||||
// Process current period events
|
// Get the day start for this event's time to ensure proper day assignment
|
||||||
|
const dayStart = this.timeManager.getDayStart(datetime);
|
||||||
|
const dateKey = dayStart.toFormat('yyyy-MM-dd');
|
||||||
|
if (!dailyStats.has(dateKey)) continue;
|
||||||
|
|
||||||
|
const dayStats = dailyStats.get(dateKey);
|
||||||
|
dayStats.orders++;
|
||||||
|
dailyStats.set(dateKey, dayStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second pass: Process filtered orders
|
||||||
|
const filterEvents = (events) => {
|
||||||
|
switch (metric) {
|
||||||
|
case 'pre_orders':
|
||||||
|
return events.filter(event => Boolean(event.event_properties?.HasPreorder));
|
||||||
|
case 'local_pickup':
|
||||||
|
return events.filter(event => Boolean(event.event_properties?.LocalPickup));
|
||||||
|
case 'on_hold':
|
||||||
|
return events.filter(event => Boolean(event.event_properties?.IsOnHold));
|
||||||
|
default:
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredCurrentEvents = filterEvents(currentEvents);
|
||||||
|
|
||||||
|
// Process current period filtered events using TimeManager's day boundaries
|
||||||
for (const event of filteredCurrentEvents) {
|
for (const event of filteredCurrentEvents) {
|
||||||
const datetime = this.timeManager.toDateTime(event.attributes?.datetime);
|
const datetime = this.timeManager.toDateTime(event.attributes?.datetime);
|
||||||
if (!datetime) continue;
|
if (!datetime) continue;
|
||||||
|
|
||||||
const dateKey = datetime.toFormat('yyyy-MM-dd');
|
// Get the day start for this event's time
|
||||||
|
const dayStart = this.timeManager.getDayStart(datetime);
|
||||||
|
const dateKey = dayStart.toFormat('yyyy-MM-dd');
|
||||||
if (!dailyStats.has(dateKey)) continue;
|
if (!dailyStats.has(dateKey)) continue;
|
||||||
|
|
||||||
const dayStats = dailyStats.get(dateKey);
|
const dayStats = dailyStats.get(dateKey);
|
||||||
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.orders++;
|
|
||||||
dayStats.itemCount += items.length;
|
|
||||||
dayStats.value += totalAmount;
|
|
||||||
dayStats.count++;
|
dayStats.count++;
|
||||||
dayStats.totalOrders = totalOrders;
|
dayStats.value += totalAmount;
|
||||||
dayStats.percentage = (dayStats.count / totalOrders) * 100;
|
dayStats.itemCount += items.length;
|
||||||
dayStats.averageOrderValue = dayStats.revenue / dayStats.orders;
|
dayStats.percentage = (dayStats.count / dayStats.orders) * 100;
|
||||||
dayStats.averageItemsPerOrder = dayStats.itemCount / dayStats.orders;
|
dayStats.averageOrderValue = dayStats.value / dayStats.count;
|
||||||
|
dayStats.averageItemsPerOrder = dayStats.itemCount / dayStats.count;
|
||||||
|
|
||||||
// Track daily order value range
|
dailyStats.set(dateKey, dayStats);
|
||||||
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 with more granular ranges
|
// Initialize and process previous period stats using TimeManager's day boundaries
|
||||||
const ranges = [
|
|
||||||
{ min: 0, max: 25 },
|
|
||||||
{ min: 25, max: 50 },
|
|
||||||
{ min: 50, max: 75 },
|
|
||||||
{ min: 75, max: 100 },
|
|
||||||
{ min: 100, max: 150 },
|
|
||||||
{ min: 150, max: 200 },
|
|
||||||
{ min: 200, max: 300 },
|
|
||||||
{ min: 300, max: 500 },
|
|
||||||
{ min: 500, max: Infinity }
|
|
||||||
];
|
|
||||||
|
|
||||||
// Initialize distribution if not exists
|
|
||||||
if (!dayStats.orderValueDistribution) {
|
|
||||||
dayStats.orderValueDistribution = ranges.map(range => ({
|
|
||||||
min: range.min,
|
|
||||||
max: range.max === Infinity ? 'Infinity' : range.max,
|
|
||||||
count: 0,
|
|
||||||
total: 0
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the appropriate range and update counts
|
|
||||||
const rangeIndex = ranges.findIndex(range =>
|
|
||||||
totalAmount >= range.min && totalAmount < range.max
|
|
||||||
);
|
|
||||||
|
|
||||||
if (rangeIndex !== -1) {
|
|
||||||
dayStats.orderValueDistribution[rangeIndex].count++;
|
|
||||||
dayStats.orderValueDistribution[rangeIndex].total += totalAmount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process previous period events
|
|
||||||
const prevDailyStats = new Map();
|
const prevDailyStats = new Map();
|
||||||
let prevDate = prevPeriodStart;
|
let prevDate = prevPeriodStart;
|
||||||
while (prevDate <= prevPeriodEnd) {
|
while (prevDate <= prevPeriodEnd) {
|
||||||
@@ -1697,37 +1641,47 @@ export class EventsService {
|
|||||||
prevDailyStats.set(dateKey, {
|
prevDailyStats.set(dateKey, {
|
||||||
date: prevDate.toISO(),
|
date: prevDate.toISO(),
|
||||||
timestamp: dateKey,
|
timestamp: dateKey,
|
||||||
revenue: 0,
|
|
||||||
orders: 0,
|
orders: 0,
|
||||||
itemCount: 0,
|
count: 0,
|
||||||
value: 0,
|
value: 0,
|
||||||
count: 0
|
percentage: 0
|
||||||
});
|
});
|
||||||
prevDate = prevDate.plus({ days: 1 });
|
prevDate = this.timeManager.getDayStart(prevDate.plus({ days: 1 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get total orders for previous period
|
// First pass for previous period: Count total orders
|
||||||
const prevTotalOrders = prevEvents.length;
|
for (const event of prevEvents) {
|
||||||
|
const datetime = this.timeManager.toDateTime(event.attributes?.datetime);
|
||||||
|
if (!datetime) continue;
|
||||||
|
|
||||||
// Process previous period events
|
const dayStart = this.timeManager.getDayStart(datetime);
|
||||||
|
const dateKey = dayStart.toFormat('yyyy-MM-dd');
|
||||||
|
if (!prevDailyStats.has(dateKey)) continue;
|
||||||
|
|
||||||
|
const dayStats = prevDailyStats.get(dateKey);
|
||||||
|
dayStats.orders++;
|
||||||
|
prevDailyStats.set(dateKey, dayStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second pass for previous period: Process filtered orders
|
||||||
|
const filteredPrevEvents = filterEvents(prevEvents);
|
||||||
for (const event of filteredPrevEvents) {
|
for (const event of filteredPrevEvents) {
|
||||||
const datetime = this.timeManager.toDateTime(event.attributes?.datetime);
|
const datetime = this.timeManager.toDateTime(event.attributes?.datetime);
|
||||||
if (!datetime) continue;
|
if (!datetime) continue;
|
||||||
|
|
||||||
const dateKey = datetime.toFormat('yyyy-MM-dd');
|
const dayStart = this.timeManager.getDayStart(datetime);
|
||||||
|
const dateKey = dayStart.toFormat('yyyy-MM-dd');
|
||||||
if (!prevDailyStats.has(dateKey)) continue;
|
if (!prevDailyStats.has(dateKey)) continue;
|
||||||
|
|
||||||
const dayStats = prevDailyStats.get(dateKey);
|
const dayStats = prevDailyStats.get(dateKey);
|
||||||
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 || [];
|
|
||||||
|
|
||||||
dayStats.revenue += totalAmount;
|
|
||||||
dayStats.orders++;
|
|
||||||
dayStats.itemCount += items.length;
|
|
||||||
dayStats.value += totalAmount;
|
|
||||||
dayStats.count++;
|
dayStats.count++;
|
||||||
dayStats.percentage = (dayStats.count / prevTotalOrders) * 100;
|
dayStats.value += totalAmount;
|
||||||
|
dayStats.percentage = (dayStats.count / dayStats.orders) * 100;
|
||||||
|
|
||||||
|
prevDailyStats.set(dateKey, dayStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map previous period data to current period days
|
// Map previous period data to current period days
|
||||||
@@ -1742,13 +1696,11 @@ export class EventsService {
|
|||||||
if (prevDayStats && currentDayStats) {
|
if (prevDayStats && currentDayStats) {
|
||||||
const dayStats = dailyStats.get(currentDayStats.timestamp);
|
const dayStats = dailyStats.get(currentDayStats.timestamp);
|
||||||
if (dayStats) {
|
if (dayStats) {
|
||||||
dayStats.prevRevenue = prevDayStats.revenue;
|
|
||||||
dayStats.prevOrders = prevDayStats.orders;
|
|
||||||
dayStats.prevItemCount = prevDayStats.itemCount;
|
|
||||||
dayStats.prevValue = prevDayStats.value;
|
dayStats.prevValue = prevDayStats.value;
|
||||||
dayStats.prevCount = prevDayStats.count;
|
dayStats.prevCount = prevDayStats.count;
|
||||||
|
dayStats.prevOrders = prevDayStats.orders;
|
||||||
dayStats.prevPercentage = prevDayStats.percentage;
|
dayStats.prevPercentage = prevDayStats.percentage;
|
||||||
dayStats.prevAvgOrderValue = prevDayStats.orders > 0 ? prevDayStats.revenue / prevDayStats.orders : 0;
|
dayStats.prevAvgOrderValue = prevDayStats.count > 0 ? prevDayStats.value / prevDayStats.count : 0;
|
||||||
dailyStats.set(currentDayStats.timestamp, dayStats);
|
dailyStats.set(currentDayStats.timestamp, dayStats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1759,29 +1711,19 @@ export class EventsService {
|
|||||||
.sort((a, b) => a.date.localeCompare(b.date))
|
.sort((a, b) => a.date.localeCompare(b.date))
|
||||||
.map(day => ({
|
.map(day => ({
|
||||||
...day,
|
...day,
|
||||||
revenue: Number(day.revenue || 0),
|
revenue: Number(day.value || 0),
|
||||||
orders: Number(day.orders || 0),
|
orders: Number(day.orders || 0),
|
||||||
itemCount: Number(day.itemCount || 0),
|
itemCount: Number(day.itemCount || 0),
|
||||||
averageOrderValue: Number(day.averageOrderValue || 0),
|
|
||||||
averageItemsPerOrder: Number(day.averageItemsPerOrder || 0),
|
|
||||||
count: Number(day.count || 0),
|
count: Number(day.count || 0),
|
||||||
value: Number(day.value || 0),
|
value: Number(day.value || 0),
|
||||||
percentage: Number(day.percentage || 0),
|
percentage: Number(day.percentage || 0),
|
||||||
totalOrders: Number(day.totalOrders || 0),
|
averageOrderValue: Number(day.averageOrderValue || 0),
|
||||||
prevRevenue: Number(day.prevRevenue || 0),
|
averageItemsPerOrder: Number(day.averageItemsPerOrder || 0),
|
||||||
prevOrders: Number(day.prevOrders || 0),
|
|
||||||
prevItemCount: Number(day.prevItemCount || 0),
|
|
||||||
prevValue: Number(day.prevValue || 0),
|
prevValue: Number(day.prevValue || 0),
|
||||||
prevCount: Number(day.prevCount || 0),
|
prevCount: Number(day.prevCount || 0),
|
||||||
|
prevOrders: Number(day.prevOrders || 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
|
|
||||||
},
|
|
||||||
orderValueDistribution: day.orderValueDistribution || []
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return stats;
|
return stats;
|
||||||
|
|||||||
@@ -532,7 +532,6 @@ const ShippingDetails = ({ data }) => {
|
|||||||
const OrderTypeDetails = ({ data, type }) => {
|
const OrderTypeDetails = ({ data, type }) => {
|
||||||
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>;
|
||||||
|
|
||||||
// Access the correct daily data using the 'type' prop
|
|
||||||
const timeSeriesData = data.map(day => ({
|
const timeSeriesData = data.map(day => ({
|
||||||
timestamp: day.timestamp,
|
timestamp: day.timestamp,
|
||||||
count: day.count,
|
count: day.count,
|
||||||
@@ -540,31 +539,16 @@ const OrderTypeDetails = ({ data, type }) => {
|
|||||||
percentage: day.percentage
|
percentage: day.percentage
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const typeLabels = {
|
const typeColors = {
|
||||||
'pre_orders': 'Pre-Orders',
|
'pre_orders': 'hsl(47.9 95.8% 53.1%)', // Yellow for pre-orders
|
||||||
'local_pickup': 'Local Pickup',
|
'local_pickup': 'hsl(192.2 70.1% 51.4%)', // Cyan for local pickup
|
||||||
'on_hold': 'On Hold'
|
'on_hold': 'hsl(346.8 77.2% 49.8%)' // Red for on hold
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const color = typeColors[type];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<StatCard
|
|
||||||
title={`Total ${typeLabels[type]}`}
|
|
||||||
value={data[0]?.totalOrders?.toLocaleString() || 0}
|
|
||||||
description={`${data[0]?.percentage?.toFixed(1) || 0}% of all orders`}
|
|
||||||
colorClass="text-blue-600 dark:text-blue-400"
|
|
||||||
icon={ShoppingCart}
|
|
||||||
/>
|
|
||||||
<StatCard
|
|
||||||
title="Total Value"
|
|
||||||
value={formatCurrency(data[0]?.value || 0)}
|
|
||||||
description={`Avg: ${formatCurrency((data[0]?.value || 0) / (data[0]?.count || 1))}`}
|
|
||||||
colorClass="text-green-600 dark:text-green-400"
|
|
||||||
icon={DollarSign}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-medium mb-4">Daily Order Count</h3>
|
<h3 className="text-lg font-medium mb-4">Daily Order Count</h3>
|
||||||
<TimeSeriesChart
|
<TimeSeriesChart
|
||||||
@@ -572,7 +556,7 @@ const OrderTypeDetails = ({ data, type }) => {
|
|||||||
dataKey="count"
|
dataKey="count"
|
||||||
name="Orders"
|
name="Orders"
|
||||||
type="bar"
|
type="bar"
|
||||||
color="hsl(221.2 83.2% 53.3%)"
|
color={color}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -582,7 +566,7 @@ const OrderTypeDetails = ({ data, type }) => {
|
|||||||
data={timeSeriesData}
|
data={timeSeriesData}
|
||||||
dataKey="value"
|
dataKey="value"
|
||||||
name="Value"
|
name="Value"
|
||||||
color="hsl(142.1 76.2% 36.3%)"
|
color={color}
|
||||||
valueFormatter={(value) => formatCurrency(value)}
|
valueFormatter={(value) => formatCurrency(value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -593,7 +577,7 @@ const OrderTypeDetails = ({ data, type }) => {
|
|||||||
data={timeSeriesData}
|
data={timeSeriesData}
|
||||||
dataKey="percentage"
|
dataKey="percentage"
|
||||||
name="Percentage"
|
name="Percentage"
|
||||||
color="hsl(262.1 83.3% 57.8%)"
|
color={color}
|
||||||
valueFormatter={(value) => `${value.toFixed(1)}%`}
|
valueFormatter={(value) => `${value.toFixed(1)}%`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -1622,7 +1606,7 @@ const StatCards = ({
|
|||||||
|
|
||||||
<StatCard
|
<StatCard
|
||||||
title="Pre-Orders"
|
title="Pre-Orders"
|
||||||
value={stats?.orderTypes?.preOrders?.percentage?.toFixed(1) || '0'}
|
value={((stats?.orderTypes?.preOrders?.count / stats?.orderCount) * 100)?.toFixed(1) || '0'}
|
||||||
valueSuffix="%"
|
valueSuffix="%"
|
||||||
description={`${stats?.orderTypes?.preOrders?.count || 0} orders`}
|
description={`${stats?.orderTypes?.preOrders?.count || 0} orders`}
|
||||||
colorClass="text-yellow-600 dark:text-yellow-400"
|
colorClass="text-yellow-600 dark:text-yellow-400"
|
||||||
@@ -1634,7 +1618,7 @@ const StatCards = ({
|
|||||||
|
|
||||||
<StatCard
|
<StatCard
|
||||||
title="Local Pickup"
|
title="Local Pickup"
|
||||||
value={stats?.orderTypes?.localPickup?.percentage?.toFixed(1) || '0'}
|
value={((stats?.orderTypes?.localPickup?.count / stats?.orderCount) * 100)?.toFixed(1) || '0'}
|
||||||
valueSuffix="%"
|
valueSuffix="%"
|
||||||
description={`${stats?.orderTypes?.localPickup?.count || 0} orders`}
|
description={`${stats?.orderTypes?.localPickup?.count || 0} orders`}
|
||||||
colorClass="text-cyan-600 dark:text-cyan-400"
|
colorClass="text-cyan-600 dark:text-cyan-400"
|
||||||
@@ -1646,7 +1630,7 @@ const StatCards = ({
|
|||||||
|
|
||||||
<StatCard
|
<StatCard
|
||||||
title="On Hold"
|
title="On Hold"
|
||||||
value={stats?.orderTypes?.heldItems?.percentage?.toFixed(1) || '0'}
|
value={((stats?.orderTypes?.heldItems?.count / stats?.orderCount) * 100)?.toFixed(1) || '0'}
|
||||||
valueSuffix="%"
|
valueSuffix="%"
|
||||||
description={`${stats?.orderTypes?.heldItems?.count || 0} orders`}
|
description={`${stats?.orderTypes?.heldItems?.count || 0} orders`}
|
||||||
colorClass="text-red-600 dark:text-red-400"
|
colorClass="text-red-600 dark:text-red-400"
|
||||||
|
|||||||
Reference in New Issue
Block a user