From f08981da31f1263039f3c38aebd48e11c5cbf84f Mon Sep 17 00:00:00 2001 From: Kazem Alghasi Date: Wed, 12 Aug 2026 03:52:35 +0330 Subject: [PATCH] feat(ui): implement modern customer dashboard Implement a new, modern customer dashboard interface including: - A new `[ifnex_customer_dashboard]` shortcode. - A redesigned sidebar with user profile information and navigation. - A statistics overview section with icon-based cards. - Modern SVG icon system (Heroicons style) for dashboard elements. - Updated CSS with a modern design language (gradients, shadows, and flexbox layouts). - Global asset enqueuing to ensure consistent styling and AJAX availability across all plugin-related pages. --- .../ifnex-bridge/assets/css/ifnex-orders.css | 131 +++++++++++ .../ifnex-bridge/includes/shortcodes.php | 203 ++++++++++++++++++ .../ifnex-bridge/includes/user-bridge.php | 31 +++ 3 files changed, 365 insertions(+) diff --git a/03_WordPress/wp-content/plugins/ifnex-bridge/assets/css/ifnex-orders.css b/03_WordPress/wp-content/plugins/ifnex-bridge/assets/css/ifnex-orders.css index 60c6797..9cd331d 100644 --- a/03_WordPress/wp-content/plugins/ifnex-bridge/assets/css/ifnex-orders.css +++ b/03_WordPress/wp-content/plugins/ifnex-bridge/assets/css/ifnex-orders.css @@ -370,4 +370,135 @@ @media print { .ifnex-detail-actions { display: none !important; } .ifnex-order-detail { max-width: 100%; } +} + +/* ═══ Modern Customer Dashboard (ifnx) ═══ */ +.ifnx-dashboard { + display: flex; gap: 24px; max-width: 1240px; margin: 0 auto; padding: 24px 0; + font-family: inherit; +} + +/* ── Sidebar ─ */ +.ifnx-sidebar { + width: 260px; flex-shrink: 0; align-self: flex-start; + background: linear-gradient(180deg, #0f172a 0%, #1e293b 100%); + border-radius: 20px; overflow: hidden; + box-shadow: 0 10px 30px rgba(15, 23, 42, 0.25); +} +.ifnx-user-card { padding: 28px 20px; text-align: center; border-bottom: 1px solid rgba(255,255,255,0.08); } +.ifnx-avatar { + width: 64px; height: 64px; margin: 0 auto 12px; border-radius: 50%; + background: linear-gradient(135deg, #f97316, #fb923c); + display: flex; align-items: center; justify-content: center; color: #fff; + box-shadow: 0 6px 18px rgba(249, 115, 22, 0.4); +} +.ifnx-user-name { color: #fff; font-weight: 700; font-size: 16px; } +.ifnx-user-email { color: rgba(255,255,255,0.55); font-size: 12px; margin-top: 4px; direction: ltr; } + +.ifnx-menu { padding: 12px 0; display: flex; flex-direction: column; } +.ifnx-menu-item { + display: flex; align-items: center; gap: 12px; + padding: 13px 22px; color: rgba(255,255,255,0.72); + text-decoration: none; font-size: 14px; font-weight: 500; + border-right: 3px solid transparent; transition: all 0.25s ease; +} +.ifnx-menu-item:hover { background: rgba(255,255,255,0.06); color: #fff; } +.ifnx-menu-item.active { + background: linear-gradient(90deg, rgba(249,115,22,0.18), transparent); + border-right-color: #f97316; color: #fff; font-weight: 700; +} +.ifnx-menu-icon { display: flex; align-items: center; } +.ifnx-menu-divider { height: 1px; background: rgba(255,255,255,0.08); margin: 10px 20px; } +.ifnx-menu-item.logout { color: #f87171; } +.ifnx-menu-item.logout:hover { background: rgba(248,113,113,0.1); color: #f87171; } + +/* ── Content ── */ +.ifnx-content { flex: 1; min-width: 0; } +.ifnx-content-header { + display: flex; justify-content: space-between; align-items: center; + margin-bottom: 20px; flex-wrap: wrap; gap: 8px; +} +.ifnx-content-header h2 { margin: 0; color: #0f172a; font-size: 22px; font-weight: 800; } +.ifnx-breadcrumb { color: #94a3b8; font-size: 13px; } + +/* ── Stats ─ */ +.ifnx-stats { + display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); + gap: 16px; margin-bottom: 24px; +} +.ifnx-stat { + background: #fff; border-radius: 16px; padding: 18px; + display: flex; align-items: center; gap: 14px; + box-shadow: 0 1px 3px rgba(15,23,42,0.06), 0 8px 24px rgba(15,23,42,0.05); + border: 1px solid #eef2f7; transition: transform 0.2s ease, box-shadow 0.2s ease; +} +.ifnx-stat:hover { transform: translateY(-3px); box-shadow: 0 12px 28px rgba(15,23,42,0.1); } +.ifnx-stat-icon { + width: 48px; height: 48px; border-radius: 14px; flex-shrink: 0; + background: var(--tint); color: var(--clr); + display: flex; align-items: center; justify-content: center; +} +.ifnx-stat-value { display: block; font-size: 20px; font-weight: 800; color: #0f172a; } +.ifnx-stat-label { display: block; font-size: 12px; color: #64748b; margin-top: 2px; } + +/* ── Cards ── */ +.ifnx-card { + background: #fff; border-radius: 16px; padding: 22px; + border: 1px solid #eef2f7; + box-shadow: 0 1px 3px rgba(15,23,42,0.06), 0 8px 24px rgba(15,23,42,0.05); +} +.ifnx-card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; } +.ifnx-card-header h3 { margin: 0; color: #0f172a; font-size: 16px; font-weight: 700; } +.ifnx-link { color: #f97316; font-size: 13px; text-decoration: none; font-weight: 600; } +.ifnx-link:hover { text-decoration: underline; } + +.ifnx-empty { text-align: center; padding: 40px 0; color: #94a3b8; } +.ifnx-empty svg { opacity: 0.4; margin-bottom: 12px; } +.ifnx-empty p { margin-bottom: 16px; } + +.ifnx-order-list { display: flex; flex-direction: column; gap: 10px; } +.ifnx-order-row { + display: flex; align-items: center; gap: 16px; flex-wrap: wrap; + padding: 14px 16px; background: #f8fafc; border-radius: 12px; + border: 1px solid #eef2f7; transition: background 0.2s; +} +.ifnx-order-row:hover { background: #f1f5f9; } +.ifnx-order-awb code { font-weight: 700; color: #0f172a; background: #fff; padding: 4px 10px; border-radius: 8px; border: 1px solid #e2e8f0; } +.ifnx-order-route { color: #64748b; font-size: 13px; flex: 1; } +.ifnx-order-amount { font-weight: 700; color: #0f172a; } +.ifnx-order-amount small { color: #94a3b8; font-weight: 400; } + +/* ── Wallet Hero ── */ +.ifnx-wallet-hero { + background: linear-gradient(135deg, #0f172a 0%, #1e293b 60%, #334155 100%); + border-radius: 20px; padding: 40px; color: #fff; text-align: center; + position: relative; overflow: hidden; + box-shadow: 0 15px 40px rgba(15,23,42,0.3); +} +.ifnx-wallet-hero::before { + content: ''; position: absolute; top: -60px; left: -60px; + width: 200px; height: 200px; border-radius: 50%; + background: radial-gradient(circle, rgba(249,115,22,0.35), transparent 70%); +} +.ifnx-wallet-label { font-size: 14px; color: rgba(255,255,255,0.65); margin-bottom: 10px; } +.ifnx-wallet-amount { font-size: 42px; font-weight: 800; } +.ifnx-wallet-amount small { font-size: 16px; font-weight: 400; color: rgba(255,255,255,0.6); } +.ifnx-wallet-actions { margin-top: 26px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } +.ifnx-wallet-btn { + background: linear-gradient(135deg, #f97316, #fb923c); color: #fff; + padding: 12px 26px; border-radius: 12px; text-decoration: none; + font-weight: 700; font-size: 14px; box-shadow: 0 6px 18px rgba(249,115,22,0.4); + transition: transform 0.2s; +} +.ifnx-wallet-btn:hover { transform: translateY(-2px); } +.ifnx-wallet-btn.ghost { background: rgba(255,255,255,0.1); box-shadow: none; border: 1px solid rgba(255,255,255,0.2); } + +/* ── Responsive ── */ +@media (max-width: 900px) { + .ifnx-dashboard { flex-direction: column; } + .ifnx-sidebar { width: 100%; } + .ifnx-menu { flex-direction: row; flex-wrap: wrap; padding: 10px; } + .ifnx-menu-item { border-right: none; border-bottom: 3px solid transparent; padding: 10px 14px; } + .ifnx-menu-item.active { border-bottom-color: #f97316; } + .ifnx-menu-divider { display: none; } } \ No newline at end of file diff --git a/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php b/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php index 86e3ffb..903cc72 100644 --- a/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php +++ b/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php @@ -1096,4 +1096,207 @@ function ifnex_order_detail_shortcode($atts) { '', + 'orders' => '', + 'plus' => '', + 'wallet' => '', + 'chart' => '', + 'tracking' => '', + 'user' => '', + 'logout' => '', + 'truck' => '', + 'check' => '', + 'clock' => '', + ]; + + $path = $icons[$name] ?? $icons['dashboard']; + + return '' . $path . ''; +} + +// ══════════════════════════════════════════════════════════════ +// شورت‌کد پنل مشتری (Customer Dashboard) +// ══════════════════════════════════════════════════════════════ + +add_shortcode('ifnex_customer_dashboard', 'ifnex_customer_dashboard_shortcode'); + +function ifnex_customer_dashboard_shortcode($atts) { + if (!is_user_logged_in()) { + ob_start(); + ?> + + get_customer_profile($user_id); + $wallet_balance = 0; $stats = []; + if (!is_wp_error($profile)) { + $wallet_balance = $profile['wallet']['balance'] ?? 0; + $stats = $profile['stats'] ?? []; + } + + $recent_orders = []; + if ($tab === 'dashboard') { + $orders_result = $bridge->get_customer_orders($user_id, 3); + if (!is_wp_error($orders_result)) $recent_orders = $orders_result['data'] ?? []; + } + + $base_url = get_permalink(); + $menu_items = [ + 'dashboard' => ['icon' => 'dashboard', 'label' => 'داشبورد'], + 'orders' => ['icon' => 'orders', 'label' => 'سفارشات من'], + 'new-order' => ['icon' => 'plus', 'label' => 'ثبت سفارش جدید'], + 'wallet' => ['icon' => 'wallet', 'label' => 'کیف پول'], + 'transactions' => ['icon' => 'chart', 'label' => 'تراکنش‌ها'], + 'tracking' => ['icon' => 'tracking', 'label' => 'رهگیری مرسوله'], + 'profile' => ['icon' => 'user', 'label' => 'پروفایل'], + ]; + + $tab_titles = [ + 'dashboard' => 'داشبورد', 'orders' => 'سفارشات من', 'new-order' => 'ثبت سفارش جدید', + 'wallet' => 'کیف پول', 'transactions' => 'تراکنش‌ها', 'tracking' => 'رهگیری مرسوله', 'profile' => 'پروفایل', + ]; + + ob_start(); + ?> +
+ + + + +
+
+

+ پنل کاربری / +
+ + +
+
+
+
+ + موجودی کیف پول (ریال) +
+
+
+
+
+ + کل سفارشات +
+
+
+
+
+ + در انتظار پرداخت +
+
+
+
+
+ + در حال پردازش +
+
+
+
+
+ + تحویل شده +
+
+
+ +
+
+

آخرین سفارشات

+ مشاهده همه ← +
+ +
+ +

هنوز سفارشی ثبت نکرده‌اید.

+ ثبت اولین سفارش +
+ +
+ +
+
+
+
ریال
+ +
+ +
+ +
+ + + + + + +
+
موجودی فعلی کیف پول
+
ریال
+ +
+ + + + + + + +
+
+ post_content, 'ifnex_user_profile') || has_shortcode($post->post_content, 'ifnex_order_payment') || has_shortcode($post->post_content, 'ifnex_order_detail'); + has_shortcode($post->post_content, 'ifnex_customer_dashboard'); if ($has_order_shortcodes) { // ✅ اصلاح: dirname(__FILE__) یک سطح بالاتر می‌رود @@ -547,4 +548,34 @@ function ifnex_enqueue_payment_assets() { 'orders_url' => home_url('/my-orders/'), )); } +} + +// ══════════════════════════════════════════════════════════════ +// لود سراسری CSS و متغیرهای AJAX برای همه صفحات IFNEX +// این تابع همیشه اجرا می‌شود تا هیچ شورت‌کدی بدون استایل نماند +// ══════════════════════════════════════════════════════════════ + +add_action('wp_enqueue_scripts', 'ifnex_enqueue_global_assets', 20); + +function ifnex_enqueue_global_assets() { + $plugin_url = plugin_dir_url(dirname(__FILE__)); + + // لود CSS اصلی (نسخه را بالا بردیم تا cache مرورگر بشکند) + wp_enqueue_style( + 'ifnex-orders-css', + $plugin_url . 'assets/css/ifnex-orders.css', + array(), + '1.4.0' + ); + + // لود jQuery + wp_enqueue_script('jquery'); + + // متغیرهای AJAX برای همه صفحات + wp_localize_script('jquery', 'ifnex_ajax', array( + 'ajax_url' => admin_url('admin-ajax.php'), + 'nonce' => wp_create_nonce('ifnex_ajax_nonce'), + 'orders_url' => home_url('/my-account/?tab=orders'), + 'home_url' => home_url('/'), + )); } \ No newline at end of file