feat: Mobile chart optimization + VIP customer settings
## Task 4: Mobile Chart Optimization ✅ **Problem:** Too many data points = tight/crowded lines on mobile **Solution:** Horizontal scroll container **Implementation:** - ChartCard component enhanced with mobile scroll - Calculates minimum width based on data points (40px per point) - Desktop: Full width responsive - Mobile: Fixed width chart in scrollable container ```tsx // ChartCard.tsx const mobileMinWidth = Math.max(600, dataPoints * 40); <div className="overflow-x-auto -mx-6 px-6 md:mx-0 md:px-0"> <div style={{ minWidth: `${mobileMinWidth}px` }}> {children} </div> </div> ``` **Benefits:** - ✅ All data visible (no loss) - ✅ Natural swipe gesture - ✅ Readable spacing - ✅ Works for all chart types - ✅ No data aggregation needed --- ## Task 5: VIP Customer Settings ✅ **New Feature:** Configure VIP customer qualification criteria ### Backend (PHP) **Files Created:** - `includes/Compat/CustomerSettingsProvider.php` - VIP settings management - VIP detection logic - Customer stats calculation **API Endpoints:** - `GET /store/customer-settings` - Fetch settings - `POST /store/customer-settings` - Save settings **Settings:** ```php woonoow_vip_min_spent = 1000 woonoow_vip_min_orders = 10 woonoow_vip_timeframe = 'all' | '30' | '90' | '365' woonoow_vip_require_both = true woonoow_vip_exclude_refunded = true ``` **VIP Detection:** ```php CustomerSettingsProvider::is_vip_customer($customer_id) CustomerSettingsProvider::get_vip_stats($customer_id) ``` ### Frontend (React) **Files Created:** - `admin-spa/src/routes/Settings/Customers.tsx` **Features:** - 💰 Minimum total spent (currency input) - �� Minimum order count (number input) - 📅 Timeframe selector (all-time, 30/90/365 days) - ⚙️ Require both criteria toggle - 🚫 Exclude refunded orders toggle - 👑 Live preview of VIP qualification **Navigation:** - Added to Settings menu - Route: `/settings/customers` - Position: After Tax, before Notifications --- ## Summary ✅ **Mobile Charts:** Horizontal scroll for readable spacing ✅ **VIP Settings:** Complete backend + frontend implementation **Mobile Chart Strategy:** - Minimum 600px width - 40px per data point - Smooth horizontal scroll - Desktop remains responsive **VIP Customer System:** - Flexible qualification criteria - Multiple timeframes - AND/OR logic support - Refunded order exclusion - Ready for customer list integration **All tasks complete!** 🎉
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
namespace WooNooW\API;
|
||||
|
||||
use WooNooW\Compat\StoreSettingsProvider;
|
||||
use WooNooW\Compat\CustomerSettingsProvider;
|
||||
use WP_REST_Controller;
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Request;
|
||||
@@ -85,6 +86,24 @@ class StoreController extends WP_REST_Controller {
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
// GET /woonoow/v1/store/customer-settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/customer-settings', [
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [$this, 'get_customer_settings'],
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
// POST /woonoow/v1/store/customer-settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/customer-settings', [
|
||||
[
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => [$this, 'save_customer_settings'],
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,6 +260,75 @@ class StoreController extends WP_REST_Controller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get customer settings
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object or error
|
||||
*/
|
||||
public function get_customer_settings(WP_REST_Request $request) {
|
||||
try {
|
||||
$settings = CustomerSettingsProvider::get_settings();
|
||||
|
||||
$response = rest_ensure_response($settings);
|
||||
$response->header('Cache-Control', 'max-age=60');
|
||||
|
||||
return $response;
|
||||
} catch (\Exception $e) {
|
||||
return new WP_Error(
|
||||
'get_customer_settings_failed',
|
||||
$e->getMessage(),
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save customer settings
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object or error
|
||||
*/
|
||||
public function save_customer_settings(WP_REST_Request $request) {
|
||||
try {
|
||||
$settings = $request->get_json_params();
|
||||
|
||||
if (empty($settings)) {
|
||||
return new WP_Error(
|
||||
'invalid_settings',
|
||||
__('Invalid settings data', 'woonoow'),
|
||||
['status' => 400]
|
||||
);
|
||||
}
|
||||
|
||||
$updated = CustomerSettingsProvider::update_settings($settings);
|
||||
|
||||
if (!$updated) {
|
||||
return new WP_Error(
|
||||
'update_failed',
|
||||
__('Failed to update customer settings', 'woonoow'),
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
|
||||
// Return updated settings
|
||||
$new_settings = CustomerSettingsProvider::get_settings();
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('Customer settings updated successfully', 'woonoow'),
|
||||
'settings' => $new_settings,
|
||||
], 200);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return new WP_Error(
|
||||
'save_customer_settings_failed',
|
||||
$e->getMessage(),
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check permission
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user