docs: Update PROGRESS_NOTE with complete dashboard analytics implementation and cleanup temporary docs

This commit is contained in:
dwindown
2025-11-04 20:01:11 +07:00
parent 919ce8684f
commit 6508a537f7
8 changed files with 273 additions and 1682 deletions

View File

@@ -1,268 +0,0 @@
# 👥 Customer Analytics - Data Logic Documentation
**Last Updated:** Nov 4, 2025 12:48 AM (GMT+7)
---
## 🎯 Overview
This document defines the business logic for Customer Analytics metrics, clarifying which data is **period-based** vs **store-level**.
---
## 📊 Stat Cards Layout
### Row 1: Period-Based Metrics (with comparisons)
```
[New Customers] [Retention Rate] [Avg Orders/Customer] [Avg Lifetime Value]
```
### Row 2: Store-Level + Segment Data
```
[Total Customers] [Returning] [VIP Customers] [At Risk]
```
---
## 📈 Metric Definitions
### 1. **New Customers** ✅ Period-Based
- **Definition:** Number of customers who made their first purchase in the selected period
- **Affected by Period:** YES
- **Has Comparison:** YES (vs previous period)
- **Logic:**
```typescript
new_customers = sum(acquisition_chart[period].new_customers)
change = ((current - previous) / previous) × 100
```
---
### 2. **Retention Rate** ✅ Period-Based
- **Definition:** Percentage of customers who returned in the selected period
- **Affected by Period:** YES
- **Has Comparison:** YES (vs previous period)
- **Logic:**
```typescript
retention_rate = (returning_customers / total_in_period) × 100
total_in_period = new_customers + returning_customers
```
- **Previous Implementation:** ❌ Was store-level (global retention)
- **Fixed:** ✅ Now calculates from period data
---
### 3. **Avg Orders/Customer** ❌ Store-Level
- **Definition:** Average number of orders per customer (all-time)
- **Affected by Period:** NO
- **Has Comparison:** NO
- **Logic:**
```typescript
avg_orders_per_customer = total_orders / total_customers
```
- **Rationale:** This is a ratio metric representing customer behavior patterns, not a time-based sum
---
### 4. **Avg Lifetime Value** ❌ Store-Level
- **Definition:** Average total revenue generated by a customer over their entire lifetime
- **Affected by Period:** NO
- **Has Comparison:** NO
- **Logic:**
```typescript
avg_ltv = total_revenue_all_time / total_customers
```
- **Previous Implementation:** ❌ Was scaled by period factor
- **Fixed:** ✅ Now always shows store-level LTV
- **Rationale:** LTV is cumulative by definition - scaling it by period makes no business sense
---
### 5. **Total Customers** ❌ Store-Level
- **Definition:** Total number of customers who have ever placed an order
- **Affected by Period:** NO
- **Has Comparison:** NO
- **Display:** Shows "All-time total" subtitle
- **Logic:**
```typescript
total_customers = data.overview.total_customers
```
- **Previous Implementation:** ❌ Was calculated from period data
- **Fixed:** ✅ Now shows all-time total
- **Rationale:** Represents store's total customer base, not acquisitions in period
---
### 6. **Returning Customers** ✅ Period-Based
- **Definition:** Number of existing customers who made repeat purchases in the selected period
- **Affected by Period:** YES
- **Has Comparison:** NO (shown as segment card)
- **Display:** Shows "In selected period" subtitle
- **Logic:**
```typescript
returning_customers = sum(acquisition_chart[period].returning_customers)
```
---
### 7. **VIP Customers** ❌ Store-Level
- **Definition:** Customers who qualify as VIP based on lifetime criteria
- **Qualification:** 10+ orders OR lifetime value > Rp5,000,000
- **Affected by Period:** NO
- **Has Comparison:** NO
- **Logic:**
```typescript
vip_customers = data.segments.vip
```
- **Rationale:** VIP status is based on cumulative lifetime behavior, not period activity
---
### 8. **At Risk Customers** ❌ Store-Level
- **Definition:** Customers with no orders in the last 90 days
- **Affected by Period:** NO
- **Has Comparison:** NO
- **Logic:**
```typescript
at_risk = data.segments.at_risk
```
- **Rationale:** At-risk status is a current state classification, not a time-based metric
---
## 📊 Charts & Tables
### Customer Acquisition Chart ✅ Period-Based
- **Data:** New vs Returning customers over time
- **Filtered by Period:** YES
- **Logic:**
```typescript
chartData = period === 'all'
? data.acquisition_chart
: data.acquisition_chart.slice(-parseInt(period))
```
---
### Lifetime Value Distribution ❌ Store-Level
- **Data:** Distribution of customers across LTV ranges
- **Filtered by Period:** NO
- **Logic:**
```typescript
ltv_distribution = data.ltv_distribution // Always all-time
```
- **Rationale:** LTV is cumulative, distribution shows overall customer value spread
---
### Top Customers Table ✅ Period-Based
- **Data:** Customers with highest spending in selected period
- **Filtered by Period:** YES
- **Logic:**
```typescript
filteredTopCustomers = period === 'all'
? data.top_customers
: data.top_customers.map(c => ({
...c,
total_spent: c.total_spent * (period / 30),
orders: c.orders * (period / 30)
}))
```
- **Previous Implementation:** ❌ Was always all-time
- **Fixed:** ✅ Now respects period selection
- **Note:** Uses global period selector (no individual toggle needed)
---
## 🔄 Comparison Logic
### When Comparisons Are Shown:
- Period is **7, 14, or 30 days**
- Metric is **period-based**
- Compares current period vs previous period of same length
### When Comparisons Are Hidden:
- Period is **"All Time"** (no previous period to compare)
- Metric is **store-level** (not time-based)
---
## 📋 Summary Table
| Metric | Type | Period-Based? | Has Comparison? | Notes |
|--------|------|---------------|-----------------|-------|
| New Customers | Period | ✅ YES | ✅ YES | Acquisitions in period |
| Retention Rate | Period | ✅ YES | ✅ YES | **FIXED** - Now period-based |
| Avg Orders/Customer | Store | ❌ NO | ❌ NO | Ratio, not sum |
| Avg Lifetime Value | Store | ❌ NO | ❌ NO | **FIXED** - Now store-level |
| Total Customers | Store | ❌ NO | ❌ NO | **FIXED** - Now all-time total |
| Returning Customers | Period | ✅ YES | ❌ NO | Segment card |
| VIP Customers | Store | ❌ NO | ❌ NO | Lifetime qualification |
| At Risk | Store | ❌ NO | ❌ NO | Current state |
| Acquisition Chart | Period | ✅ YES | - | Filtered by period |
| LTV Distribution | Store | ❌ NO | - | All-time distribution |
| Top Customers Table | Period | ✅ YES | - | **FIXED** - Now filtered |
---
## ✅ Changes Made
### 1. **Total Customers**
- **Before:** Calculated from period data (new + returning)
- **After:** Shows all-time total from `data.overview.total_customers`
- **Reason:** Represents store's customer base, not period acquisitions
### 2. **Avg Lifetime Value**
- **Before:** Scaled by period factor `avg_ltv * (period / 30)`
- **After:** Always shows store-level `data.overview.avg_ltv`
- **Reason:** LTV is cumulative by definition, cannot be period-based
### 3. **Retention Rate**
- **Before:** Store-level `data.overview.retention_rate`
- **After:** Calculated from period data `(returning / total_in_period) × 100`
- **Reason:** More useful to see retention in specific periods
### 4. **Top Customers Table**
- **Before:** Always showed all-time data
- **After:** Filtered by selected period
- **Reason:** Useful to see top spenders in specific timeframes
### 5. **Card Layout Reordered**
- **Row 1:** Period-based metrics with comparisons
- **Row 2:** Store-level + segment data
- **Reason:** Better visual grouping and user understanding
---
## 🎯 Business Value
### Period-Based Metrics Answer:
- "How many new customers did we acquire this week?"
- "What's our retention rate for the last 30 days?"
- "Who are our top spenders this month?"
### Store-Level Metrics Answer:
- "How many total customers do we have?"
- "What's the average lifetime value of our customers?"
- "How many VIP customers do we have?"
- "How many customers are at risk of churning?"
---
## 🔮 Future Enhancements
### Custom Date Range (Planned)
When custom date range is implemented:
- Period-based metrics will calculate from custom range
- Store-level metrics remain unchanged
- Comparisons will be hidden (no "previous custom range")
### Real API Integration
Current implementation uses dummy data with period scaling. Real API will:
- Fetch period-specific data from backend
- Calculate metrics server-side
- Return proper comparison data
---
**Status:** ✅ Complete - All customer analytics metrics now have correct business logic!

View File

@@ -1,274 +0,0 @@
# 📊 Dashboard API Implementation Guide
**Last Updated:** Nov 4, 2025 10:50 AM (GMT+7)
---
## ✅ Frontend Implementation Complete
### **Implemented Pages (6/7):**
1.**Customers.tsx** - Full API integration
2.**Revenue.tsx** - Full API integration
3.**Orders.tsx** - Full API integration
4.**Products.tsx** - Full API integration
5.**Coupons.tsx** - Full API integration
6.**Taxes.tsx** - Full API integration
7. ⚠️ **Dashboard/index.tsx** - Partial (has syntax issues, but builds)
### **Features Implemented:**
- ✅ API integration via `useAnalytics` hook
- ✅ Loading states with spinner
- ✅ Error states with `ErrorCard` and retry functionality
- ✅ Dummy data toggle (works seamlessly)
- ✅ TypeScript type safety
- ✅ React Query caching
- ✅ Proper React Hooks ordering
---
## 🔌 Backend API Structure
### **Created Files:**
#### `/includes/Api/AnalyticsController.php`
Main controller handling all analytics endpoints.
**Registered Endpoints:**
```
GET /wp-json/woonoow/v1/analytics/overview
GET /wp-json/woonoow/v1/analytics/revenue?granularity=day
GET /wp-json/woonoow/v1/analytics/orders
GET /wp-json/woonoow/v1/analytics/products
GET /wp-json/woonoow/v1/analytics/customers
GET /wp-json/woonoow/v1/analytics/coupons
GET /wp-json/woonoow/v1/analytics/taxes
```
**Current Status:**
- All endpoints return `501 Not Implemented` error
- This triggers frontend to use dummy data
- Ready for actual implementation
#### `/includes/Api/Routes.php`
Updated to register `AnalyticsController::register_routes()`
---
## 🎯 Next Steps: Backend Implementation
### **Phase 1: Revenue Analytics** (Highest Priority)
**Endpoint:** `GET /analytics/revenue`
**Query Strategy:**
```php
// Use WooCommerce HPOS tables
global $wpdb;
// Query wp_wc_orders table
$orders = $wpdb->get_results("
SELECT
DATE(date_created_gmt) as date,
SUM(total_amount) as gross,
SUM(total_amount - tax_amount) as net,
SUM(tax_amount) as tax,
COUNT(*) as orders
FROM {$wpdb->prefix}wc_orders
WHERE status IN ('wc-completed', 'wc-processing')
AND date_created_gmt >= DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY DATE(date_created_gmt)
ORDER BY date ASC
");
```
**Expected Response Format:**
```json
{
"overview": {
"gross_revenue": 125000000,
"net_revenue": 112500000,
"tax": 12500000,
"refunds": 2500000,
"avg_order_value": 250000
},
"chart_data": [
{
"date": "2025-10-05",
"gross": 4500000,
"net": 4050000,
"tax": 450000,
"refunds": 100000,
"shipping": 50000
}
],
"by_product": [...],
"by_category": [...],
"by_payment_method": [...],
"by_shipping_method": [...]
}
```
### **Phase 2: Orders Analytics**
**Key Metrics to Calculate:**
- Total orders by status
- Fulfillment rate
- Cancellation rate
- Average processing time
- Orders by day of week
- Orders by hour
**HPOS Tables:**
- `wp_wc_orders` - Main orders table
- `wp_wc_order_operational_data` - Status changes, timestamps
### **Phase 3: Customers Analytics**
**Key Metrics:**
- New vs returning customers
- Customer retention rate
- Average orders per customer
- Customer lifetime value (LTV)
- VIP customers (high spenders)
- At-risk customers (inactive)
**Data Sources:**
- `wp_wc_orders` - Order history
- `wp_wc_customer_lookup` - Customer aggregates (if using WC Analytics)
- Custom queries for LTV calculation
### **Phase 4: Products Analytics**
**Key Metrics:**
- Top selling products
- Revenue by product
- Revenue by category
- Stock analysis (low stock, out of stock)
- Product performance trends
**Data Sources:**
- `wp_wc_order_product_lookup` - Product sales data
- `wp_posts` + `wp_postmeta` - Product data
- `wp_term_relationships` - Categories
### **Phase 5: Coupons & Taxes**
**Coupons:**
- Usage statistics
- Discount amounts
- Revenue generated with coupons
- Top performing coupons
**Taxes:**
- Tax collected by rate
- Tax by location
- Orders with tax
---
## 📝 Implementation Checklist
### **For Each Endpoint:**
- [ ] Write HPOS-compatible queries
- [ ] Add date range filtering
- [ ] Implement caching (transients)
- [ ] Add error handling
- [ ] Test with real WooCommerce data
- [ ] Optimize query performance
- [ ] Add query result pagination if needed
- [ ] Document response format
### **Performance Considerations:**
1. **Use Transients for Caching:**
```php
$cache_key = 'woonoow_revenue_' . md5(serialize($params));
$data = get_transient($cache_key);
if (false === $data) {
$data = self::calculate_revenue_metrics($params);
set_transient($cache_key, $data, HOUR_IN_SECONDS);
}
```
2. **Limit Date Ranges:**
- Default to last 30 days
- Max 1 year for performance
3. **Use Indexes:**
- Ensure HPOS tables have proper indexes
- Add custom indexes if needed
4. **Async Processing:**
- For heavy calculations, use Action Scheduler
- Pre-calculate daily aggregates
---
## 🧪 Testing Strategy
### **Manual Testing:**
1. Toggle dummy data OFF in dashboard
2. Verify loading states appear
3. Check error messages are clear
4. Test retry functionality
5. Verify data displays correctly
### **API Testing:**
```bash
# Test endpoint
curl -X GET "http://woonoow.local/wp-json/woonoow/v1/analytics/revenue" \
-H "Authorization: Bearer YOUR_TOKEN"
# Expected: 501 error (not implemented)
# After implementation: 200 with data
```
---
## 📚 Reference Files
### **Frontend:**
- `admin-spa/src/hooks/useAnalytics.ts` - Data fetching hook
- `admin-spa/src/lib/analyticsApi.ts` - API endpoint definitions
- `admin-spa/src/routes/Dashboard/Customers.tsx` - Reference implementation
### **Backend:**
- `includes/Api/AnalyticsController.php` - Main controller
- `includes/Api/Routes.php` - Route registration
- `includes/Api/Permissions.php` - Permission checks
---
## 🎯 Success Criteria
✅ **Frontend:**
- All pages load without errors
- Dummy data toggle works smoothly
- Loading states are clear
- Error messages are helpful
- Build succeeds without TypeScript errors
✅ **Backend (To Do):**
- All endpoints return real data
- Queries are performant (<1s response time)
- Data matches frontend expectations
- Caching reduces database load
- Error handling is robust
---
## 📊 Current Build Status
```
✓ built in 3.71s
Exit code: 0
```
**All dashboard pages are production-ready with dummy data fallback!**
---
**Next Action:** Start implementing `AnalyticsController::get_revenue()` method with real HPOS queries.

View File

@@ -1,372 +0,0 @@
# 🔌 Dashboard Analytics - API Integration Guide
**Created:** Nov 4, 2025 9:21 AM (GMT+7)
---
## 🎯 Overview
Dashboard now supports **real data from API** with a toggle to switch between real and dummy data for development/testing.
**Default:** Real data (dummy data toggle OFF)
---
## 📁 Files Created
### 1. **Analytics API Module**
**File:** `/admin-spa/src/lib/analyticsApi.ts`
Defines all analytics endpoints:
```typescript
export const AnalyticsApi = {
overview: (params?: AnalyticsParams) => api.get('/woonoow/v1/analytics/overview', params),
revenue: (params?: AnalyticsParams) => api.get('/woonoow/v1/analytics/revenue', params),
orders: (params?: AnalyticsParams) => api.get('/woonoow/v1/analytics/orders', params),
products: (params?: AnalyticsParams) => api.get('/woonoow/v1/analytics/products', params),
customers: (params?: AnalyticsParams) => api.get('/woonoow/v1/analytics/customers', params),
coupons: (params?: AnalyticsParams) => api.get('/woonoow/v1/analytics/coupons', params),
taxes: (params?: AnalyticsParams) => api.get('/woonoow/v1/analytics/taxes', params),
};
```
### 2. **Analytics Hooks**
**File:** `/admin-spa/src/hooks/useAnalytics.ts`
React Query hooks for each endpoint:
```typescript
// Generic hook
useAnalytics(endpoint, dummyData, additionalParams)
// Specific hooks
useRevenueAnalytics(dummyData, granularity?)
useOrdersAnalytics(dummyData)
useProductsAnalytics(dummyData)
useCustomersAnalytics(dummyData)
useCouponsAnalytics(dummyData)
useTaxesAnalytics(dummyData)
useOverviewAnalytics(dummyData)
```
---
## 🔄 How It Works
### 1. **Context State**
```typescript
// DashboardContext.tsx
const [useDummyData, setUseDummyData] = useState(false); // Default: real data
```
### 2. **Hook Logic**
```typescript
// useAnalytics.ts
const { data, isLoading, error } = useQuery({
queryKey: ['analytics', endpoint, period, additionalParams],
queryFn: async () => {
const params = { period: period === 'all' ? undefined : period, ...additionalParams };
return await AnalyticsApi[endpoint](params);
},
enabled: !useDummy, // Only fetch when NOT using dummy data
staleTime: 5 * 60 * 1000, // 5 minutes
});
// Return dummy data if toggle is on, otherwise return API data
return {
data: useDummy ? dummyData : (data || dummyData),
isLoading: useDummy ? false : isLoading,
error: useDummy ? null : error,
};
```
### 3. **Component Usage**
```typescript
// Before (old way)
const { period, useDummy } = useDashboardPeriod();
const data = useDummy ? DUMMY_DATA : DUMMY_DATA; // Always dummy!
// After (new way)
const { period } = useDashboardPeriod();
const { data, isLoading, error } = useCustomersAnalytics(DUMMY_CUSTOMERS_DATA);
// Loading state
if (isLoading) return <LoadingSpinner />;
// Error state
if (error) return <ErrorMessage error={error} />;
// Use data normally
```
---
## 📊 API Endpoints Required
### Backend PHP REST API Routes
All endpoints should be registered under `/woonoow/v1/analytics/`:
#### 1. **Overview** - `GET /woonoow/v1/analytics/overview`
**Query Params:**
- `period`: '7', '14', '30', or omit for all-time
- `start_date`: ISO date (for custom range)
- `end_date`: ISO date (for custom range)
**Response:** Same structure as `DUMMY_DATA` in `Dashboard/index.tsx`
---
#### 2. **Revenue** - `GET /woonoow/v1/analytics/revenue`
**Query Params:**
- `period`: '7', '14', '30', or omit for all-time
- `granularity`: 'day', 'week', 'month'
**Response:** Same structure as `DUMMY_REVENUE_DATA`
---
#### 3. **Orders** - `GET /woonoow/v1/analytics/orders`
**Query Params:**
- `period`: '7', '14', '30', or omit for all-time
**Response:** Same structure as `DUMMY_ORDERS_DATA`
---
#### 4. **Products** - `GET /woonoow/v1/analytics/products`
**Query Params:**
- `period`: '7', '14', '30', or omit for all-time
**Response:** Same structure as `DUMMY_PRODUCTS_DATA`
---
#### 5. **Customers** - `GET /woonoow/v1/analytics/customers`
**Query Params:**
- `period`: '7', '14', '30', or omit for all-time
**Response:** Same structure as `DUMMY_CUSTOMERS_DATA`
---
#### 6. **Coupons** - `GET /woonoow/v1/analytics/coupons`
**Query Params:**
- `period`: '7', '14', '30', or omit for all-time
**Response:** Same structure as `DUMMY_COUPONS_DATA`
---
#### 7. **Taxes** - `GET /woonoow/v1/analytics/taxes`
**Query Params:**
- `period`: '7', '14', '30', or omit for all-time
**Response:** Same structure as `DUMMY_TAXES_DATA`
---
## 🔧 Backend Implementation Guide
### Step 1: Register REST Routes
```php
// includes/Admin/Analytics/AnalyticsController.php
namespace WooNooW\Admin\Analytics;
class AnalyticsController {
public function register_routes() {
register_rest_route('woonoow/v1', '/analytics/overview', [
'methods' => 'GET',
'callback' => [$this, 'get_overview'],
'permission_callback' => [$this, 'check_permission'],
]);
register_rest_route('woonoow/v1', '/analytics/revenue', [
'methods' => 'GET',
'callback' => [$this, 'get_revenue'],
'permission_callback' => [$this, 'check_permission'],
]);
// ... register other endpoints
}
public function check_permission() {
return current_user_can('manage_woocommerce');
}
public function get_overview(\WP_REST_Request $request) {
$period = $request->get_param('period');
$start_date = $request->get_param('start_date');
$end_date = $request->get_param('end_date');
// Calculate date range
$dates = $this->calculate_date_range($period, $start_date, $end_date);
// Fetch data from WooCommerce
$data = [
'metrics' => $this->get_overview_metrics($dates),
'salesChart' => $this->get_sales_chart($dates),
'orderStatusDistribution' => $this->get_order_status_distribution($dates),
'lowStock' => $this->get_low_stock_products(),
];
return rest_ensure_response($data);
}
private function calculate_date_range($period, $start_date, $end_date) {
if ($start_date && $end_date) {
return ['start' => $start_date, 'end' => $end_date];
}
if (!$period) {
// All time
return ['start' => null, 'end' => null];
}
$days = intval($period);
$end = current_time('Y-m-d');
$start = date('Y-m-d', strtotime("-{$days} days"));
return ['start' => $start, 'end' => $end];
}
// ... implement other methods
}
```
### Step 2: Query WooCommerce Data
```php
private function get_overview_metrics($dates) {
global $wpdb;
$where = $this->build_date_where_clause($dates);
// Use HPOS tables
$orders_table = $wpdb->prefix . 'wc_orders';
$query = "
SELECT
COUNT(*) as total_orders,
SUM(total_amount) as total_revenue,
AVG(total_amount) as avg_order_value
FROM {$orders_table}
WHERE status IN ('wc-completed', 'wc-processing')
{$where}
";
$results = $wpdb->get_row($query);
// Calculate comparison with previous period
$previous_metrics = $this->get_previous_period_metrics($dates);
return [
'revenue' => [
'today' => floatval($results->total_revenue),
'yesterday' => floatval($previous_metrics->total_revenue),
'change' => $this->calculate_change_percent(
$results->total_revenue,
$previous_metrics->total_revenue
),
],
// ... other metrics
];
}
```
---
## 🎨 Frontend Implementation
### Example: Update Revenue.tsx
```typescript
import { useRevenueAnalytics } from '@/hooks/useAnalytics';
import { DUMMY_REVENUE_DATA } from './data/dummyRevenue';
export default function RevenueAnalytics() {
const { period } = useDashboardPeriod();
const [granularity, setGranularity] = useState<'day' | 'week' | 'month'>('day');
// Fetch real data or use dummy data
const { data, isLoading, error } = useRevenueAnalytics(DUMMY_REVENUE_DATA, granularity);
if (isLoading) return <LoadingSpinner />;
if (error) return <ErrorMessage error={error} />;
// Use data normally...
}
```
---
## 🔀 Toggle Behavior
### When Dummy Data Toggle is OFF (default):
1. ✅ Fetches real data from API
2. ✅ Shows loading spinner while fetching
3. ✅ Shows error message if API fails
4. ✅ Caches data for 5 minutes (React Query)
5. ✅ Automatically refetches when period changes
### When Dummy Data Toggle is ON:
1. ✅ Uses dummy data immediately (no API call)
2. ✅ No loading state
3. ✅ No error state
4. ✅ Perfect for development/testing
---
## 📋 Migration Checklist
### Frontend (React):
- [x] Create `analyticsApi.ts` with all endpoints
- [x] Create `useAnalytics.ts` hooks
- [x] Update `DashboardContext` default to `false`
- [x] Update `Customers.tsx` as example
- [ ] Update `Revenue.tsx`
- [ ] Update `Orders.tsx`
- [ ] Update `Products.tsx`
- [ ] Update `Coupons.tsx`
- [ ] Update `Taxes.tsx`
- [ ] Update `Dashboard/index.tsx` (overview)
### Backend (PHP):
- [ ] Create `AnalyticsController.php`
- [ ] Register REST routes
- [ ] Implement `/analytics/overview`
- [ ] Implement `/analytics/revenue`
- [ ] Implement `/analytics/orders`
- [ ] Implement `/analytics/products`
- [ ] Implement `/analytics/customers`
- [ ] Implement `/analytics/coupons`
- [ ] Implement `/analytics/taxes`
- [ ] Add permission checks
- [ ] Add data caching (transients)
- [ ] Add error handling
---
## 🚀 Benefits
1. **Real-time Data**: Dashboard shows actual store data
2. **Development Friendly**: Toggle to dummy data for testing
3. **Performance**: React Query caching reduces API calls
4. **Error Handling**: Graceful fallback to dummy data
5. **Type Safety**: TypeScript interfaces match API responses
6. **Maintainable**: Single source of truth for API endpoints
---
## 🔮 Future Enhancements
1. **Custom Date Range**: Add date picker for custom ranges
2. **Export Data**: Download analytics as CSV/PDF
3. **Real-time Updates**: WebSocket for live data
4. **Comparison Mode**: Compare multiple periods side-by-side
5. **Scheduled Reports**: Email reports automatically
---
**Status:** ✅ Frontend ready - Backend implementation needed!

View File

@@ -1,507 +0,0 @@
# 📊 Dashboard Implementation Guide
**Last updated:** 2025-11-03 14:50 GMT+7
**Status:** In Progress
**Reference:** DASHBOARD_PLAN.md
---
## 🎯 Overview
This document tracks the implementation of the WooNooW Dashboard module with all submenus as planned in DASHBOARD_PLAN.md. We're implementing a **dummy data toggle system** to allow visualization of charts even when stores have no data yet.
---
## ✅ Completed
### 1. Main Dashboard (`/dashboard`) ✅
**Status:** Complete with dummy data
**File:** `admin-spa/src/routes/Dashboard/index.tsx`
**Features:**
- ✅ 4 metric cards (Revenue, Orders, Avg Order Value, Conversion Rate)
- ✅ Unified period selector (7/14/30 days)
- ✅ Interactive Sales Overview chart (Revenue/Orders/Both)
- ✅ Interactive Order Status pie chart with dropdown
- ✅ Top Products & Customers (tabbed)
- ✅ Low Stock Alert banner (edge-to-edge)
- ✅ Fully responsive (desktop/tablet/mobile)
- ✅ Dark mode support
- ✅ Proper currency formatting
### 2. Dummy Data Toggle System ✅
**Status:** Complete
**Files:**
- `admin-spa/src/lib/useDummyData.ts` - Zustand store with persistence
- `admin-spa/src/components/DummyDataToggle.tsx` - Toggle button component
**Features:**
- ✅ Global state management with Zustand
- ✅ LocalStorage persistence
- ✅ Toggle button in dashboard header
- ✅ Visual indicator (Database icon vs DatabaseZap icon)
- ✅ Works across all dashboard pages
**Usage:**
```typescript
import { useDummyData } from '@/lib/useDummyData';
function MyComponent() {
const useDummy = useDummyData();
const data = useDummy ? DUMMY_DATA : realData;
// ...
}
```
---
## 🚧 In Progress
### Shared Components
Creating reusable components for all dashboard pages:
#### Components to Create:
- [ ] `StatCard.tsx` - Metric card with trend indicator
- [ ] `ChartCard.tsx` - Chart container with title and filters
- [ ] `DataTable.tsx` - Sortable, searchable table
- [ ] `DateRangePicker.tsx` - Custom date range selector
- [ ] `ComparisonToggle.tsx` - Compare with previous period
- [ ] `ExportButton.tsx` - CSV/PDF export functionality
- [ ] `LoadingSkeleton.tsx` - Loading states for charts/tables
- [ ] `EmptyState.tsx` - No data messages
---
## 📋 Pending Implementation
### 1. Revenue Report (`/dashboard/revenue`)
**Priority:** High
**Estimated Time:** 2-3 days
**Features to Implement:**
- [ ] Revenue chart with granularity selector (daily/weekly/monthly)
- [ ] Gross vs Net revenue comparison
- [ ] Revenue breakdown tables:
- [ ] By Product
- [ ] By Category
- [ ] By Payment Method
- [ ] By Shipping Method
- [ ] Tax collected display
- [ ] Refunds tracking
- [ ] Comparison mode (vs previous period)
- [ ] Export functionality
**Dummy Data Structure:**
```typescript
{
overview: {
gross_revenue: number,
net_revenue: number,
tax: number,
shipping: number,
refunds: number,
change_percent: number
},
chart_data: Array<{
date: string,
gross: number,
net: number,
refunds: number
}>,
by_product: Array<{
id: number,
name: string,
revenue: number,
orders: number,
refunds: number
}>,
by_category: Array<{
id: number,
name: string,
revenue: number,
percentage: number
}>,
by_payment_method: Array<{
method: string,
orders: number,
revenue: number
}>,
by_shipping_method: Array<{
method: string,
orders: number,
revenue: number
}>
}
```
---
### 2. Orders Analytics (`/dashboard/orders`)
**Priority:** High
**Estimated Time:** 2-3 days
**Features to Implement:**
- [ ] Orders timeline chart
- [ ] Status breakdown pie chart
- [ ] Orders by hour heatmap
- [ ] Orders by day of week chart
- [ ] Average processing time
- [ ] Fulfillment rate metric
- [ ] Cancellation rate metric
- [ ] Filters (status, payment method, date range)
**Dummy Data Structure:**
```typescript
{
overview: {
total_orders: number,
avg_order_value: number,
fulfillment_rate: number,
cancellation_rate: number,
avg_processing_time: string
},
chart_data: Array<{
date: string,
orders: number,
completed: number,
cancelled: number
}>,
by_status: Array<{
status: string,
count: number,
percentage: number,
color: string
}>,
by_hour: Array<{
hour: number,
orders: number
}>,
by_day_of_week: Array<{
day: string,
orders: number
}>
}
```
---
### 3. Products Performance (`/dashboard/products`)
**Priority:** Medium
**Estimated Time:** 3-4 days
**Features to Implement:**
- [ ] Top products table (sortable by revenue/quantity/views)
- [ ] Category performance breakdown
- [ ] Product trends chart (multi-select products)
- [ ] Stock analysis:
- [ ] Low stock items
- [ ] Out of stock items
- [ ] Slow movers (overstocked)
- [ ] Search and filters
- [ ] Export functionality
**Dummy Data Structure:**
```typescript
{
overview: {
items_sold: number,
revenue: number,
avg_price: number,
low_stock_count: number,
out_of_stock_count: number
},
top_products: Array<{
id: number,
name: string,
image: string,
items_sold: number,
revenue: number,
stock: number,
status: string,
views: number
}>,
by_category: Array<{
id: number,
name: string,
products_count: number,
revenue: number,
items_sold: number
}>,
stock_analysis: {
low_stock: Array<Product>,
out_of_stock: Array<Product>,
slow_movers: Array<Product>
}
}
```
---
### 4. Customers Analytics (`/dashboard/customers`)
**Priority:** Medium
**Estimated Time:** 3-4 days
**Features to Implement:**
- [ ] Customer segments (New, Returning, VIP, At-Risk)
- [ ] Top customers table
- [ ] Customer acquisition chart
- [ ] Lifetime value analysis
- [ ] Retention rate metric
- [ ] Average orders per customer
- [ ] Search and filters
**Dummy Data Structure:**
```typescript
{
overview: {
total_customers: number,
new_customers: number,
returning_customers: number,
avg_ltv: number,
retention_rate: number,
avg_orders_per_customer: number
},
segments: {
new: number,
returning: number,
vip: number,
at_risk: number
},
top_customers: Array<{
id: number,
name: string,
email: string,
orders: number,
total_spent: number,
avg_order_value: number,
last_order_date: string,
segment: string
}>,
acquisition_chart: Array<{
date: string,
new_customers: number,
returning_customers: number
}>,
ltv_distribution: Array<{
range: string,
count: number
}>
}
```
---
### 5. Coupons Report (`/dashboard/coupons`)
**Priority:** Low
**Estimated Time:** 2 days
**Features to Implement:**
- [ ] Coupon performance table
- [ ] Usage chart over time
- [ ] ROI calculation
- [ ] Top coupons (most used, highest revenue, best ROI)
- [ ] Filters and search
**Dummy Data Structure:**
```typescript
{
overview: {
total_discount: number,
coupons_used: number,
revenue_with_coupons: number,
avg_discount_per_order: number
},
coupons: Array<{
id: number,
code: string,
type: string,
amount: number,
uses: number,
discount_amount: number,
revenue_generated: number,
roi: number
}>,
usage_chart: Array<{
date: string,
uses: number,
discount: number
}>
}
```
---
### 6. Taxes Report (`/dashboard/taxes`)
**Priority:** Low
**Estimated Time:** 1-2 days
**Features to Implement:**
- [ ] Tax summary (total collected)
- [ ] Tax by rate breakdown
- [ ] Tax by location (country/state)
- [ ] Tax collection chart
- [ ] Export for accounting
**Dummy Data Structure:**
```typescript
{
overview: {
total_tax: number,
avg_tax_per_order: number,
orders_with_tax: number
},
by_rate: Array<{
rate: string,
percentage: number,
orders: number,
tax_amount: number
}>,
by_location: Array<{
country: string,
state: string,
orders: number,
tax_amount: number
}>,
chart_data: Array<{
date: string,
tax: number
}>
}
```
---
## 🗂️ File Structure
```
admin-spa/src/
├── routes/
│ └── Dashboard/
│ ├── index.tsx ✅ Main overview (complete)
│ ├── Revenue.tsx ⏳ Revenue report (pending)
│ ├── Orders.tsx ⏳ Orders analytics (pending)
│ ├── Products.tsx ⏳ Product performance (pending)
│ ├── Customers.tsx ⏳ Customer analytics (pending)
│ ├── Coupons.tsx ⏳ Coupon reports (pending)
│ ├── Taxes.tsx ⏳ Tax reports (pending)
│ ├── components/
│ │ ├── StatCard.tsx ⏳ Metric card (pending)
│ │ ├── ChartCard.tsx ⏳ Chart container (pending)
│ │ ├── DataTable.tsx ⏳ Sortable table (pending)
│ │ ├── DateRangePicker.tsx ⏳ Date selector (pending)
│ │ ├── ComparisonToggle.tsx ⏳ Compare mode (pending)
│ │ └── ExportButton.tsx ⏳ Export (pending)
│ └── data/
│ ├── dummyRevenue.ts ⏳ Revenue dummy data (pending)
│ ├── dummyOrders.ts ⏳ Orders dummy data (pending)
│ ├── dummyProducts.ts ⏳ Products dummy data (pending)
│ ├── dummyCustomers.ts ⏳ Customers dummy data (pending)
│ ├── dummyCoupons.ts ⏳ Coupons dummy data (pending)
│ └── dummyTaxes.ts ⏳ Taxes dummy data (pending)
├── components/
│ ├── DummyDataToggle.tsx ✅ Toggle button (complete)
│ └── ui/
│ ├── tabs.tsx ✅ Tabs component (complete)
│ └── tooltip.tsx ⏳ Tooltip (needs @radix-ui package)
└── lib/
└── useDummyData.ts ✅ Dummy data store (complete)
```
---
## 🔧 Technical Stack
**Frontend:**
- React 18 + TypeScript
- Recharts 3.3.0 (charts)
- TanStack Query (data fetching)
- Zustand (state management)
- Shadcn UI (components)
- Tailwind CSS (styling)
**Backend (Future):**
- REST API endpoints (`/woonoow/v1/analytics/*`)
- HPOS tables integration
- Query optimization with caching
- Transients for expensive queries
---
## 📅 Implementation Timeline
### Week 1: Foundation ✅
- [x] Main Dashboard with dummy data
- [x] Dummy data toggle system
- [x] Shared component planning
### Week 2: Shared Components (Current)
- [ ] Create all shared components
- [ ] Create dummy data files
- [ ] Set up routing for submenus
### Week 3: Revenue & Orders
- [ ] Revenue report page
- [ ] Orders analytics page
- [ ] Export functionality
### Week 4: Products & Customers
- [ ] Products performance page
- [ ] Customers analytics page
- [ ] Advanced filters
### Week 5: Coupons & Taxes
- [ ] Coupons report page
- [ ] Taxes report page
- [ ] Final polish
### Week 6: Real Data Integration
- [ ] Create backend API endpoints
- [ ] Wire all pages to real data
- [ ] Keep dummy data toggle for demos
- [ ] Performance optimization
---
## 🎯 Next Steps
### Immediate (This Week):
1. ✅ Create dummy data toggle system
2. ⏳ Create shared components (StatCard, ChartCard, DataTable)
3. ⏳ Set up routing for all dashboard submenus
4. ⏳ Create dummy data files for each page
### Short Term (Next 2 Weeks):
1. Implement Revenue report page
2. Implement Orders analytics page
3. Add export functionality
4. Add comparison mode
### Long Term (Month 2):
1. Implement remaining pages (Products, Customers, Coupons, Taxes)
2. Create backend API endpoints
3. Wire to real data
4. Performance optimization
5. User testing
---
## 📝 Notes
### Dummy Data Toggle Benefits:
1. **Development:** Easy to test UI without real data
2. **Demos:** Show potential to clients/stakeholders
3. **New Stores:** Visualize what analytics will look like
4. **Testing:** Consistent data for testing edge cases
### Design Principles:
1. **Consistency:** All pages follow same design language
2. **Performance:** Lazy load routes, optimize queries
3. **Accessibility:** Keyboard navigation, screen readers
4. **Responsiveness:** Mobile-first approach
5. **UX:** Clear loading states, helpful empty states
---
**Status:** Ready to proceed with shared components and submenu pages!
**Next Action:** Create shared components (StatCard, ChartCard, DataTable)

View File

@@ -1,207 +0,0 @@
# 📊 Dashboard Stat Cards & Tables Audit
**Generated:** Nov 4, 2025 12:03 AM (GMT+7)
---
## 🎯 Rules for Period-Based Data:
### ✅ Should Have Comparison (change prop):
- Period is NOT "all"
- Period is NOT custom date range (future)
- Data is time-based (affected by period)
### ❌ Should NOT Have Comparison:
- Period is "all" (no previous period)
- Period is custom date range (future)
- Data is global/store-level (not time-based)
---
## 📄 Page 1: Dashboard (index.tsx)
### Stat Cards:
| # | Title | Value Source | Affected by Period? | Has Comparison? | Status |
|---|-------|--------------|---------------------|-----------------|--------|
| 1 | Revenue | `periodMetrics.revenue.current` | ✅ YES | ✅ YES | ✅ CORRECT |
| 2 | Orders | `periodMetrics.orders.current` | ✅ YES | ✅ YES | ✅ CORRECT |
| 3 | Avg Order Value | `periodMetrics.avgOrderValue.current` | ✅ YES | ✅ YES | ✅ CORRECT |
| 4 | Conversion Rate | `DUMMY_DATA.metrics.conversionRate.today` | ✅ YES | ✅ YES | ⚠️ NEEDS FIX - Not using periodMetrics |
### Other Metrics:
- **Low Stock Alert**: ❌ NOT period-based (global inventory)
---
## 📄 Page 2: Revenue Analytics (Revenue.tsx)
### Stat Cards:
| # | Title | Value Source | Affected by Period? | Has Comparison? | Status |
|---|-------|--------------|---------------------|-----------------|--------|
| 1 | Gross Revenue | `periodMetrics.gross_revenue` | ✅ YES | ✅ YES | ✅ CORRECT |
| 2 | Net Revenue | `periodMetrics.net_revenue` | ✅ YES | ✅ YES | ✅ CORRECT |
| 3 | Tax Collected | `periodMetrics.tax` | ✅ YES | ❌ NO | ⚠️ NEEDS FIX - Should have comparison |
| 4 | Refunds | `periodMetrics.refunds` | ✅ YES | ❌ NO | ⚠️ NEEDS FIX - Should have comparison |
### Tables:
| # | Title | Data Source | Affected by Period? | Status |
|---|-------|-------------|---------------------|--------|
| 1 | Top Products | `filteredProducts` | ✅ YES | ✅ CORRECT |
| 2 | Revenue by Category | `filteredCategories` | ✅ YES | ✅ CORRECT |
| 3 | Payment Methods | `filteredPaymentMethods` | ✅ YES | ✅ CORRECT |
| 4 | Shipping Methods | `filteredShippingMethods` | ✅ YES | ✅ CORRECT |
---
## 📄 Page 3: Orders Analytics (Orders.tsx)
### Stat Cards:
| # | Title | Value Source | Affected by Period? | Has Comparison? | Status |
|---|-------|--------------|---------------------|-----------------|--------|
| 1 | Total Orders | `periodMetrics.total_orders` | ✅ YES | ✅ YES | ✅ CORRECT |
| 2 | Avg Order Value | `periodMetrics.avg_order_value` | ✅ YES | ❌ NO | ⚠️ NEEDS FIX - Should have comparison |
| 3 | Fulfillment Rate | `periodMetrics.fulfillment_rate` | ✅ YES | ❌ NO | ⚠️ NEEDS FIX - Should have comparison |
| 4 | Cancellation Rate | `periodMetrics.cancellation_rate` | ✅ YES | ❌ NO | ⚠️ NEEDS FIX - Should have comparison |
### Other Metrics:
- **Avg Processing Time**: ✅ YES (period-based average) - ⚠️ NEEDS comparison
- **Performance Summary**: ✅ YES (period-based) - Already has text summary
---
## 📄 Page 4: Products Performance (Products.tsx)
### Stat Cards:
| # | Title | Value Source | Affected by Period? | Has Comparison? | Status |
|---|-------|--------------|---------------------|-----------------|--------|
| 1 | Items Sold | `periodMetrics.items_sold` | ✅ YES | ✅ YES | ✅ CORRECT |
| 2 | Revenue | `periodMetrics.revenue` | ✅ YES | ✅ YES | ✅ CORRECT |
| 3 | Low Stock | `data.overview.low_stock_count` | ❌ NO (Global) | ❌ NO | ✅ CORRECT |
| 4 | Out of Stock | `data.overview.out_of_stock_count` | ❌ NO (Global) | ❌ NO | ✅ CORRECT |
### Tables:
| # | Title | Data Source | Affected by Period? | Status |
|---|-------|-------------|---------------------|--------|
| 1 | Top Products | `filteredProducts` | ✅ YES | ✅ CORRECT |
| 2 | Products by Category | `filteredCategories` | ✅ YES | ✅ CORRECT |
| 3 | Stock Analysis | `data.stock_analysis` | ❌ NO (Global) | ✅ CORRECT |
---
## 📄 Page 5: Customers Analytics (Customers.tsx)
### Stat Cards:
| # | Title | Value Source | Affected by Period? | Has Comparison? | Status |
|---|-------|--------------|---------------------|-----------------|--------|
| 1 | Total Customers | `periodMetrics.total_customers` | ✅ YES | ✅ YES | ✅ CORRECT |
| 2 | Avg Lifetime Value | `periodMetrics.avg_ltv` | ✅ YES | ❌ NO | ⚠️ NEEDS FIX - Should have comparison |
| 3 | Retention Rate | `periodMetrics.retention_rate` | ❌ NO (Percentage) | ❌ NO | ✅ CORRECT |
| 4 | Avg Orders/Customer | `periodMetrics.avg_orders_per_customer` | ❌ NO (Average) | ❌ NO | ✅ CORRECT |
### Segment Cards:
| # | Title | Value Source | Affected by Period? | Status |
|---|-------|--------------|---------------------|--------|
| 1 | New Customers | `periodMetrics.new_customers` | ✅ YES | ✅ CORRECT |
| 2 | Returning Customers | `periodMetrics.returning_customers` | ✅ YES | ✅ CORRECT |
| 3 | VIP Customers | `data.segments.vip` | ❌ NO (Global) | ✅ CORRECT |
| 4 | At Risk | `data.segments.at_risk` | ❌ NO (Global) | ✅ CORRECT |
### Tables:
| # | Title | Data Source | Affected by Period? | Status |
|---|-------|-------------|---------------------|--------|
| 1 | Top Customers | `data.top_customers` | ❌ NO (Global LTV) | ✅ CORRECT |
---
## 📄 Page 6: Coupons Report (Coupons.tsx)
### Stat Cards:
| # | Title | Value Source | Affected by Period? | Has Comparison? | Status |
|---|-------|--------------|---------------------|-----------------|--------|
| 1 | Total Discount | `periodMetrics.total_discount` | ✅ YES | ✅ YES | ✅ CORRECT |
| 2 | Coupons Used | `periodMetrics.coupons_used` | ✅ YES | ✅ YES | ✅ CORRECT |
| 3 | Revenue with Coupons | `periodMetrics.revenue_with_coupons` | ✅ YES | ❌ NO | ⚠️ NEEDS FIX - Should have comparison |
| 4 | Avg Discount/Order | `periodMetrics.avg_discount_per_order` | ✅ YES | ❌ NO | ⚠️ NEEDS FIX - Should have comparison |
### Tables:
| # | Title | Data Source | Affected by Period? | Status |
|---|-------|-------------|---------------------|--------|
| 1 | Coupon Performance | `filteredCoupons` | ✅ YES | ✅ CORRECT |
---
## 📄 Page 7: Taxes Report (Taxes.tsx)
### Stat Cards:
| # | Title | Value Source | Affected by Period? | Has Comparison? | Status |
|---|-------|--------------|---------------------|-----------------|--------|
| 1 | Total Tax Collected | `periodMetrics.total_tax` | ✅ YES | ✅ YES | ✅ CORRECT |
| 2 | Avg Tax per Order | `periodMetrics.avg_tax_per_order` | ✅ YES | ❌ NO | ⚠️ NEEDS FIX - Should have comparison |
| 3 | Orders with Tax | `periodMetrics.orders_with_tax` | ✅ YES | ❌ NO | ⚠️ NEEDS FIX - Should have comparison |
### Tables:
| # | Title | Data Source | Affected by Period? | Status |
|---|-------|-------------|---------------------|--------|
| 1 | Tax by Rate | `filteredByRate` | ✅ YES | ✅ CORRECT |
| 2 | Tax by Location | `filteredByLocation` | ✅ YES | ✅ CORRECT |
---
## 📋 Summary - ALL ISSUES FIXED! ✅
### ✅ FIXED (13 items):
**Dashboard (index.tsx):**
1. ✅ Conversion Rate - Now using periodMetrics with proper comparison
**Revenue.tsx:**
2. ✅ Tax Collected - Added comparison (`tax_change`)
3. ✅ Refunds - Added comparison (`refunds_change`)
**Orders.tsx:**
4. ✅ Avg Order Value - Added comparison (`avg_order_value_change`)
5. ✅ Fulfillment Rate - Added comparison (`fulfillment_rate_change`)
6. ✅ Cancellation Rate - Added comparison (`cancellation_rate_change`)
7. ✅ Avg Processing Time - Displayed in card (not StatCard, no change needed)
**Customers.tsx:**
8. ✅ Avg Lifetime Value - Added comparison (`avg_ltv_change`)
**Coupons.tsx:**
9. ✅ Revenue with Coupons - Added comparison (`revenue_with_coupons_change`)
10. ✅ Avg Discount/Order - Added comparison (`avg_discount_per_order_change`)
**Taxes.tsx:**
11. ✅ Avg Tax per Order - Added comparison (`avg_tax_per_order_change`)
12. ✅ Orders with Tax - Added comparison (`orders_with_tax_change`)
---
## ✅ Correct Implementation (41 items total):
- ✅ All 13 stat cards now have proper period comparisons
- ✅ All tables are correctly filtered by period
- ✅ Global/store-level data correctly excluded from period filtering
- ✅ All primary metrics have proper comparisons
- ✅ Stock data remains global (correct)
- ✅ Customer segments (VIP/At Risk) remain global (correct)
- ✅ "All Time" period correctly shows no comparison (undefined)
- ✅ Build successful with no errors
---
## 🎯 Comparison Logic Implemented:
**For period-based data (7/14/30 days):**
- Current period data vs. previous period data
- Example: 7 days compares last 7 days vs. previous 7 days
- Percentage change calculated and displayed with trend indicator
**For "All Time" period:**
- No comparison shown (change = undefined)
- StatCard component handles undefined gracefully
- No "vs previous period" text displayed
---
**Status:** ✅ COMPLETE - All dashboard stat cards now have consistent comparison logic!

View File

@@ -1,37 +0,0 @@
# WooNooW Keyboard Shortcut Plan
This document lists all keyboard shortcuts planned for the WooNooW admin SPA.
Each item includes its purpose, proposed key binding, and implementation status.
## Global Shortcuts
- [ ] **Toggle Fullscreen Mode**`Ctrl + Shift + F` or `Cmd + Shift + F`
- Focus: Switch between fullscreen and normal layout
- Implementation target: useFullscreen() hook
- [ ] **Quick Search**`/`
- Focus: Focus on global search bar (future top search input)
- [ ] **Navigate to Dashboard**`D`
- Focus: Jump to Dashboard route
- [ ] **Navigate to Orders**`O`
- Focus: Jump to Orders route
- [ ] **Refresh Current View**`R`
- Focus: Soft refresh current SPA route (refetch query)
- [ ] **Open Command Palette**`Ctrl + K` or `Cmd + K`
- Focus: Open a unified command palette for navigation/actions
## Page-Level Shortcuts
- [ ] **Orders Page New Order**`N`
- Focus: Trigger order creation modal (future enhancement)
- [ ] **Orders Page Filter**`F`
- Focus: Focus on filter dropdown
- [ ] **Dashboard Toggle Stats Range**`T`
- Focus: Switch dashboard stats range (Today / Week / Month)
---
✅ *This checklist will be updated as each shortcut is implemented.*

View File

@@ -1789,4 +1789,276 @@ const data = useDummy ? DUMMY_DATA : realApiData;
---
**Last synced:** 20251103 21:05 GMT+7
**Next milestone:** Wire Dashboard to real data OR Products module.
**Next milestone:** Wire Dashboard to real data OR Products module.# 📊 Dashboard Analytics Implementation — November 4, 2025
## ✅ COMPLETE - All 7 Analytics Pages with Real Data
**Status:** Production Ready
**Implementation:** Full HPOS integration with 5-minute caching
**Total Lines:** ~1200 lines (AnalyticsController.php)
### 🎯 Implemented Pages
#### **1. Overview** (`/analytics/overview`)
- ✅ Sales chart (revenue + orders over time) with **filled dates**
- ✅ Top 5 products by revenue
- ✅ Top 5 customers by spending
- ✅ Order status distribution (pie chart with sorting)
- ✅ Key metrics: Revenue, Orders, Avg Order Value, **Conversion Rate**
#### **2. Revenue** (`/analytics/revenue`)
- ✅ Revenue chart (gross, net, tax, refunds, shipping)
- ✅ Top 10 products by revenue
- 📋 Revenue by category (TODO)
- 📋 Revenue by payment method (TODO)
- 📋 Revenue by shipping method (TODO)
#### **3. Orders** (`/analytics/orders`)
- ✅ Orders over time (total + by status)
- ✅ Orders by status (sorted by importance)
- ✅ Orders by hour of day (24h breakdown)
- ✅ Orders by day of week
- ✅ Average processing time (human-readable)
- ✅ Fulfillment rate & Cancellation rate
#### **4. Products** (`/analytics/products`)
- ✅ Top 20 products by revenue
- ✅ Stock analysis (low stock, out of stock counts)
- ✅ Average price calculation
- 📋 Conversion rate placeholder (0.00)
#### **5. Customers** (`/analytics/customers`)
- ✅ Top 20 customers by spending
- ✅ New vs Returning customers
- ✅ Customer segments
- ✅ Average LTV (Lifetime Value)
- ✅ Average orders per customer
#### **6. Coupons** (`/analytics/coupons`)
- ✅ Coupon usage chart over time
- ✅ Top coupons by discount amount
- ✅ **ROI calculation** (Revenue Generated / Discount Given)
- ✅ Coupon performance metrics
#### **7. Taxes** (`/analytics/taxes`)
- ✅ Tax chart over time
- ✅ Total tax collected
- ✅ Average tax per order
- ✅ Orders with tax count
---
## 🔧 Key Features Implemented
### **1. Conversion Rate Calculation**
**Formula:** `(Completed Orders / Total Orders) × 100`
**Example:**
- 10 orders total
- 3 completed
- Conversion Rate = 30.00%
**Location:** `AnalyticsController.php` lines 383-406
```php
$total_all_orders = 0;
$completed_orders = 0;
foreach ($orderStatusDistribution as $status) {
$total_all_orders += $count;
if ($status->status === 'wc-completed') {
$completed_orders = $count;
}
}
$conversion_rate = $total_all_orders > 0
? round(($completed_orders / $total_all_orders) * 100, 2)
: 0.00;
```
---
### **2. Fill All Dates in Charts**
**Best Practice:** Show all dates in range, even with no data
**Implementation:** `AnalyticsController.php` lines 324-358
```php
// Create a map of existing data
$data_map = [];
foreach ($salesChart as $row) {
$data_map[$row->date] = [
'revenue' => round(floatval($row->revenue), 2),
'orders' => intval($row->orders),
];
}
// Fill in ALL dates in the range
for ($i = $days - 1; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-{$i} days"));
if (isset($data_map[$date])) {
$revenue = $data_map[$date]['revenue'];
$orders = $data_map[$date]['orders'];
} else {
// No data for this date, fill with zeros
$revenue = 0.00;
$orders = 0;
}
$formatted_sales[] = [
'date' => $date,
'revenue' => $revenue,
'orders' => $orders,
];
}
```
**Benefits:**
- ✅ Shows complete timeline (no gaps)
- ✅ Weekends/holidays with no orders are visible
- ✅ Accurate trend visualization
- ✅ Matches Google Analytics, Shopify standards
---
### **3. Frontend Improvements**
#### **Conversion Rate Display**
- ✅ Uses real API data (no dummy fallback)
- ✅ Formatted as percentage with 2 decimals
- ✅ Shows comparison for non-"all time" periods
#### **Low Stock Alert**
- ✅ Hides when count is zero
- ✅ Shows actual count from API
- ✅ No dummy data fallback
**Location:** `admin-spa/src/routes/Dashboard/index.tsx`
```typescript
// Conversion rate from real data
const currentConversionRate = data?.metrics?.conversionRate?.today ?? 0;
// Low stock alert - hide if zero
{(data?.lowStock?.length ?? 0) > 0 && (
<div className="alert">
{data?.lowStock?.length ?? 0} products need attention
</div>
)}
```
---
### **4. Chart Visualization**
**Sales Overview Chart:**
- ✅ Area chart for revenue (gradient fill)
- ✅ Line chart with dots for orders
- ✅ Balanced visual hierarchy
- ✅ Professional appearance
**Order Status Pie Chart:**
- ✅ Sorted by importance (completed first)
- ✅ Auto-selection of first status
- ✅ Interactive hover states
- ✅ Color-coded by status
---
## 📊 API Endpoints
All endpoints support caching (5 minutes):
1. `GET /woonoow/v1/analytics/overview?period=30`
2. `GET /woonoow/v1/analytics/revenue?period=30&granularity=day`
3. `GET /woonoow/v1/analytics/orders?period=30`
4. `GET /woonoow/v1/analytics/products?period=30`
5. `GET /woonoow/v1/analytics/customers?period=30`
6. `GET /woonoow/v1/analytics/coupons?period=30`
7. `GET /woonoow/v1/analytics/taxes?period=30`
**Period Options:** `7`, `14`, `30`, `all`
---
## 🎨 UI/UX Features
- ✅ Period selector (Last 7/14/30 days, All time)
- ✅ Real Data toggle (switches between real and dummy data)
- ✅ Responsive design (mobile-first)
- ✅ Dark mode support
- ✅ Loading states
- ✅ Error handling
- ✅ Empty states
- ✅ Metric cards with comparison
- ✅ Professional charts (Recharts)
- ✅ Consistent styling (Shadcn UI)
---
## 📚 Files Changed
### Backend (PHP)
- `includes/Api/AnalyticsController.php` - Complete implementation (~1200 lines)
- `includes/Api/Routes.php` - 7 new endpoints
### Frontend (React/TypeScript)
- `admin-spa/src/routes/Dashboard/index.tsx` - Overview page
- `admin-spa/src/routes/Dashboard/Revenue.tsx` - Revenue page
- `admin-spa/src/routes/Dashboard/Orders.tsx` - Orders analytics
- `admin-spa/src/routes/Dashboard/Products.tsx` - Products analytics
- `admin-spa/src/routes/Dashboard/Customers.tsx` - Customers analytics
- `admin-spa/src/routes/Dashboard/Coupons.tsx` - Coupons analytics
- `admin-spa/src/routes/Dashboard/Taxes.tsx` - Taxes analytics
- `admin-spa/src/hooks/useAnalytics.ts` - Shared analytics hook
---
## 🐛 Fixes Applied
1. ✅ **Recharts prop warning** - Changed from function to string-based `dataKey`/`nameKey`
2.**Conversion rate dummy data** - Now uses real API data
3.**Low stock alert** - Hides when zero
4.**Date gaps in charts** - All dates filled with zeros
5.**"All time" comparison** - Suppressed for all time period
6.**Percentage formatting** - Consistent 2 decimal places
---
## 🎯 Next Steps (Optional Enhancements)
1. **Revenue by Category** - Group products by category
2. **Revenue by Payment Method** - Breakdown by gateway
3. **Revenue by Shipping Method** - Breakdown by shipping
4. **Product Conversion Rate** - Track views → purchases
5. **Customer Retention Rate** - Calculate repeat purchase rate
6. **Previous Period Comparison** - Calculate "yesterday" metrics
7. **Export to CSV** - Download analytics data
8. **Date Range Picker** - Custom date selection
9. **Real-time Updates** - WebSocket or polling
10. **Dashboard Widgets** - Customizable widget system
---
## ✅ Success Criteria - ALL MET
- [x] 7 analytics pages implemented
- [x] Real HPOS data integration
- [x] Caching (5 minutes)
- [x] Conversion rate calculation
- [x] Fill all dates in charts
- [x] ROI calculation for coupons
- [x] Responsive design
- [x] Dark mode support
- [x] Error handling
- [x] Loading states
- [x] No dummy data fallbacks in Real Data mode
- [x] Professional UI/UX
---
**Implementation Date:** November 4, 2025
**Total Development Time:** ~6 hours
**Status:** ✅ Production Ready
**Next Milestone:** Products module OR Settings module

View File

@@ -1,16 +0,0 @@
## Catatan Tambahan
Jika kamu ingin hanya isi plugin (tanpa folder dist, scripts, dsb.), jalankan perintah ini dari root project dan ganti argumen zip:
```js
execSync('zip -r dist/woonoow.zip woonoow.php includes admin-spa customer-spa composer.json package.json phpcs.xml README.md', { stdio: 'inherit' });
```
Coba ganti isi file scripts/package-zip.mjs dengan versi di atas, lalu jalankan:
```bash
node scripts/package-zip.mjs
```
Kalau sukses, kamu akan melihat log:
```
✅ Packed: dist/woonoow.zip
```