feat: Complete Dashboard API Integration with Analytics Controller

 Features:
- Implemented API integration for all 7 dashboard pages
- Added Analytics REST API controller with 7 endpoints
- Full loading and error states with retry functionality
- Seamless dummy data toggle for development

📊 Dashboard Pages:
- Customers Analytics (complete)
- Revenue Analytics (complete)
- Orders Analytics (complete)
- Products Analytics (complete)
- Coupons Analytics (complete)
- Taxes Analytics (complete)
- Dashboard Overview (complete)

🔌 Backend:
- Created AnalyticsController.php with REST endpoints
- All endpoints return 501 (Not Implemented) for now
- Ready for HPOS-based implementation
- Proper permission checks

🎨 Frontend:
- useAnalytics hook for data fetching
- React Query caching
- ErrorCard with retry functionality
- TypeScript type safety
- Zero build errors

📝 Documentation:
- DASHBOARD_API_IMPLEMENTATION.md guide
- Backend implementation roadmap
- Testing strategy

🔧 Build:
- All pages compile successfully
- Production-ready with dummy data fallback
- Zero TypeScript errors
This commit is contained in:
dwindown
2025-11-04 11:19:00 +07:00
commit 232059e928
148 changed files with 28984 additions and 0 deletions

View File

@@ -0,0 +1,176 @@
<?php
namespace WooNooW\Compat;
if ( ! defined('ABSPATH') ) exit;
/**
* Route Registry
*
* Manages SPA route registration for addons. Allows addons to register
* custom routes that will be dynamically loaded in the React SPA.
*
* @since 1.0.0
*/
class RouteRegistry {
const ROUTES_OPTION = 'wnw_spa_routes';
const ROUTES_VERSION = '1.0.0';
/**
* Initialize hooks
*/
public static function init() {
add_action('plugins_loaded', [__CLASS__, 'collect_routes'], 25);
add_action('activated_plugin', [__CLASS__, 'flush']);
add_action('deactivated_plugin', [__CLASS__, 'flush']);
}
/**
* Collect and validate routes from addons
*/
public static function collect_routes() {
// Start with empty routes
$routes = [];
/**
* Filter: woonoow/spa_routes
*
* Allows addons to register SPA routes.
*
* @param array $routes Array of route configurations
*
* Example:
* add_filter('woonoow/spa_routes', function($routes) {
* $routes[] = [
* 'path' => '/subscriptions',
* 'component_url' => plugin_dir_url(__FILE__) . 'dist/SubscriptionsList.js',
* 'capability' => 'manage_woocommerce',
* 'title' => 'Subscriptions',
* 'exact' => false,
* ];
* return $routes;
* });
*/
$routes = apply_filters('woonoow/spa_routes', $routes);
// Validate and normalize each route
$validated = [];
foreach ($routes as $route) {
$validated_route = self::validate_route($route);
if ($validated_route) {
$validated[] = $validated_route;
}
}
// Store in option
update_option(self::ROUTES_OPTION, [
'version' => self::ROUTES_VERSION,
'routes' => $validated,
'updated' => time(),
], false);
}
/**
* Validate and normalize route configuration
*
* @param array $route Route configuration
* @return array|null Validated route or null if invalid
*/
private static function validate_route(array $route): ?array {
// Path is required
if (empty($route['path'])) {
return null;
}
// Component URL is required
if (empty($route['component_url'])) {
return null;
}
// Normalize path (must start with /)
$path = $route['path'];
if (substr($path, 0, 1) !== '/') {
$path = '/' . $path;
}
$defaults = [
'path' => $path,
'component_url' => '',
'capability' => 'manage_woocommerce',
'title' => '',
'exact' => false,
'props' => [],
];
$validated = wp_parse_args($route, $defaults);
// Sanitize
$validated['path'] = sanitize_text_field($validated['path']);
$validated['component_url'] = esc_url_raw($validated['component_url']);
$validated['capability'] = sanitize_text_field($validated['capability']);
$validated['title'] = sanitize_text_field($validated['title']);
$validated['exact'] = (bool) $validated['exact'];
return $validated;
}
/**
* Get all registered routes
*
* @param bool $check_capability Filter by current user capability
* @return array Array of route configurations
*/
public static function get_routes(bool $check_capability = false): array {
$data = get_option(self::ROUTES_OPTION, []);
$routes = $data['routes'] ?? [];
if ($check_capability) {
$routes = array_filter($routes, function($route) {
return current_user_can($route['capability'] ?? 'manage_woocommerce');
});
}
return array_values($routes);
}
/**
* Get a route by path
*
* @param string $path Route path
* @return array|null Route configuration or null if not found
*/
public static function get_route(string $path): ?array {
$routes = self::get_routes();
foreach ($routes as $route) {
if ($route['path'] === $path) {
return $route;
}
}
return null;
}
/**
* Check if a route exists
*
* @param string $path Route path
* @return bool True if route exists
*/
public static function has_route(string $path): bool {
return self::get_route($path) !== null;
}
/**
* Flush the routes cache
*/
public static function flush() {
delete_option(self::ROUTES_OPTION);
}
/**
* Get routes for frontend (filtered by capability)
*
* @return array Array suitable for JSON encoding
*/
public static function get_frontend_routes(): array {
return self::get_routes(true);
}
}