feat: Fill missing dates in charts + no-data states

## Task 1: Fill Missing Dates in Chart Data 

**Issue:** Charts only show dates with actual data, causing:
- Gaps in timeline
- Tight/crowded lines on mobile
- Inconsistent X-axis

**Solution:** Backend now fills ALL dates in range with zeros

**Files Updated:**
- `includes/Api/AnalyticsController.php`
  - `calculate_revenue_metrics()` - Revenue chart
  - `calculate_orders_metrics()` - Orders chart
  - `calculate_coupons_metrics()` - Coupons chart

**Implementation:**
```php
// Create data map from query results
$data_map = [];
foreach ($chart_data_raw as $row) {
    $data_map[$row->date] = [...];
}

// Fill ALL dates in range
for ($i = $days - 1; $i >= 0; $i--) {
    $date = date('Y-m-d', strtotime("-{$i} days"));
    if (isset($data_map[$date])) {
        // Use real data
    } else {
        // Fill with zeros
    }
}
```

**Result:**
-  Consistent X-axis with all dates
-  No gaps in timeline
-  Better mobile display (evenly spaced)

---

## Task 2: No-Data States for Charts 

**Issue:** Charts show broken/empty state when no data

**Solution:** Show friendly message like Overview does

**Files Updated:**
- `admin-spa/src/routes/Dashboard/Revenue.tsx`
- `admin-spa/src/routes/Dashboard/Orders.tsx`
- `admin-spa/src/routes/Dashboard/Coupons.tsx`

**Implementation:**
```tsx
{chartData.length === 0 || chartData.every(d => d.value === 0) ? (
  <div className="flex items-center justify-center h-[300px]">
    <div className="text-center">
      <Package className="w-12 h-12 text-muted-foreground mx-auto mb-3" />
      <p className="text-muted-foreground font-medium">
        No {type} data available
      </p>
      <p className="text-sm text-muted-foreground mt-1">
        Data will appear once you have {action}
      </p>
    </div>
  </div>
) : (
  <ResponsiveContainer>...</ResponsiveContainer>
)}
```

**Result:**
-  Revenue: "No revenue data available"
-  Orders: "No orders data available"
-  Coupons: "No coupon usage data available"
-  Consistent with Overview page
-  User-friendly empty states

---

## Summary

 **Backend:** All dates filled in chart data
 **Frontend:** No-data states added to 3 charts
 **UX:** Consistent, professional empty states

**Next:** VIP customer settings + mobile chart optimization
This commit is contained in:
dwindown
2025-11-11 00:37:22 +07:00
parent 0aafb65ec0
commit 8fd3691975
4 changed files with 115 additions and 21 deletions

View File

@@ -534,20 +534,39 @@ class AnalyticsController {
$total_tax = 0;
$total_refunds = 0;
$order_count = 0;
$chart_data = [];
// Create a map of existing data by date
$data_map = [];
foreach ($chart_data_raw as $row) {
$gross = round(floatval($row->gross), 2);
$net = round(floatval($row->net), 2);
$tax = round(floatval($row->tax), 2);
$data_map[$row->date] = [
'gross' => round(floatval($row->gross), 2),
'net' => round(floatval($row->net), 2),
'tax' => round(floatval($row->tax), 2),
];
}
// Fill in ALL dates in the range (including dates with no data)
$chart_data = [];
for ($i = $days - 1; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-{$i} days"));
if (isset($data_map[$date])) {
$gross = $data_map[$date]['gross'];
$net = $data_map[$date]['net'];
$tax = $data_map[$date]['tax'];
} else {
// No data for this date, fill with zeros
$gross = 0.00;
$net = 0.00;
$tax = 0.00;
}
$total_gross += $gross;
$total_net += $net;
$total_tax += $tax;
// Format for frontend
$chart_data[] = [
'date' => $row->date,
'date' => $date,
'gross' => $gross,
'net' => $net,
'tax' => $tax,
@@ -930,11 +949,10 @@ class AnalyticsController {
LIMIT %d
", $days));
// Format chart data
$formatted_chart = [];
// Format chart data - Create a map of existing data by date
$data_map = [];
foreach ($chart_data as $row) {
$formatted_chart[] = [
'date' => $row->date,
$data_map[$row->date] = [
'orders' => intval($row->orders),
'completed' => intval($row->completed),
'processing' => intval($row->processing),
@@ -945,6 +963,28 @@ class AnalyticsController {
];
}
// Fill in ALL dates in the range (including dates with no data)
$formatted_chart = [];
for ($i = $days - 1; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-{$i} days"));
if (isset($data_map[$date])) {
$formatted_chart[] = array_merge(['date' => $date], $data_map[$date]);
} else {
// No data for this date, fill with zeros
$formatted_chart[] = [
'date' => $date,
'orders' => 0,
'completed' => 0,
'processing' => 0,
'pending' => 0,
'cancelled' => 0,
'refunded' => 0,
'failed' => 0,
];
}
}
// Calculate average order value and rates
$avg_order_value = $total_orders > 0 ? round($total_revenue / $total_orders, 2) : 0;
@@ -1189,21 +1229,39 @@ class AnalyticsController {
ORDER BY date ASC
", $days));
$formatted_chart = [];
// Create a map of existing data by date
$data_map = [];
$revenue_with_coupons = 0;
foreach ($usage_chart as $row) {
$revenue = round(floatval($row->revenue), 2);
$revenue_with_coupons += $revenue;
$formatted_chart[] = [
'date' => $row->date,
$data_map[$row->date] = [
'uses' => intval($row->uses),
'discount' => round(floatval($row->discount), 2),
'revenue' => $revenue,
];
}
// Fill in ALL dates in the range (including dates with no data)
$formatted_chart = [];
for ($i = $days - 1; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-{$i} days"));
if (isset($data_map[$date])) {
$formatted_chart[] = array_merge(['date' => $date], $data_map[$date]);
} else {
// No data for this date, fill with zeros
$formatted_chart[] = [
'date' => $date,
'uses' => 0,
'discount' => 0.00,
'revenue' => 0.00,
];
}
}
$avg_discount_per_order = $total_uses > 0 ? round($total_discount / $total_uses, 2) : 0;
return [