From 0d04c89e9159ce8bc744445235967950a5927f9d Mon Sep 17 00:00:00 2001 From: Kazem Alghasi Date: Sat, 8 Aug 2026 04:11:03 +0330 Subject: [PATCH] refactor(admin): reorganize filament navigation and layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor the Filament admin panel structure by adjusting navigation sorting across various resources to improve usability and logical grouping. - Reorder navigation items in 'مالی' (Finance), 'تنظیمات' (Settings), and 'عملیات' (Operations) groups. - Hide `PriceTestPage` from the main navigation sidebar. - Adjust sidebar width and max content width in `AdminPanelProvider`. - Add custom CSS asset for Filament styling. --- 04_Laravel/.phpunit.result.cache | 2 +- .../app/Filament/Pages/PriceTestPage.php | 3 +- .../Filament/Resources/CountryResource.php | 1 + .../Resources/DiscountCodeResource.php | 2 +- .../Filament/Resources/PaymentResource.php | 2 +- .../Resources/ShipmentItemResource.php | 1 + .../Filament/Resources/ShipmentResource.php | 1 + .../Resources/ShippingRateResource.php | 1 + .../app/Filament/Resources/WalletResource.php | 2 +- .../Resources/WalletTransactionResource.php | 2 +- .../Providers/Filament/AdminPanelProvider.php | 4 +- 04_Laravel/resources/css/filament.css | 287 ++++++++++++++++++ 12 files changed, 301 insertions(+), 7 deletions(-) create mode 100644 04_Laravel/resources/css/filament.css diff --git a/04_Laravel/.phpunit.result.cache b/04_Laravel/.phpunit.result.cache index aa6a7d5..d0d88f4 100644 --- a/04_Laravel/.phpunit.result.cache +++ b/04_Laravel/.phpunit.result.cache @@ -1 +1 @@ -{"version":2,"defects":{"Tests\\Feature\\Api\\PricingControllerTest::it_can_calculate_pricing_with_valid_data":5,"Tests\\Feature\\Api\\PricingControllerTest::it_returns_validation_errors_for_invalid_data":7,"Tests\\Feature\\Services\\PriceCalculatorServiceTest::it_calculates_price_correctly_for_standard_package":8,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_returns_active_discount_codes":8,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_validates_discount_code_successfully":8,"Tests\\Feature\\Api\\PaymentControllerTest::it_completes_mock_payment_successfully":7,"Tests\\Feature\\Services\\WalletServiceTest::it_creates_deposit_transaction":8,"Tests\\Feature\\Services\\WalletServiceTest::it_completes_deposit_and_updates_balance":8,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_deposit":8,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_withdrawal":8,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_withdrawal_when_balance_is_insufficient":7,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_order_payment":8,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_order_payment_when_balance_is_insufficient":7,"Tests\\Feature\\Services\\WalletServiceTest::it_fails_transaction":8},"times":{"Tests\\Feature\\Api\\PricingControllerTest::it_can_calculate_pricing_with_valid_data":0.055,"Tests\\Feature\\Api\\PricingControllerTest::it_returns_validation_errors_for_invalid_data":0.052,"Tests\\Feature\\Services\\PriceCalculatorServiceTest::it_calculates_price_correctly_for_standard_package":0.009,"Tests\\Unit\\ExampleTest::test_that_true_is_true":0.006,"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":0.056,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_returns_active_discount_codes":0.09,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_validates_discount_code_successfully":0.059,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_invalid_discount_code":0.052,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_expired_discount_code":0.055,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_code_below_minimum_order_amount":0.048,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_calculates_fixed_discount_correctly":0.048,"Tests\\Feature\\Api\\PaymentControllerTest::it_redirects_to_gateway_for_payment":0.067,"Tests\\Feature\\Api\\PaymentControllerTest::it_validates_minimum_deposit_amount":0.054,"Tests\\Feature\\Api\\PaymentControllerTest::it_prevents_payment_for_frozen_wallet":0.05,"Tests\\Feature\\Api\\PaymentControllerTest::it_completes_mock_payment_successfully":0.079,"Tests\\Feature\\Api\\PaymentControllerTest::it_checks_transaction_status":0.051,"Tests\\Feature\\Services\\WalletServiceTest::it_creates_deposit_transaction":0.005,"Tests\\Feature\\Services\\WalletServiceTest::it_completes_deposit_and_updates_balance":0.008,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_deposit":0.004,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_withdrawal":0.004,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_withdrawal_when_balance_is_insufficient":0.002,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_order_payment":0.004,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_order_payment_when_balance_is_insufficient":0.001,"Tests\\Feature\\Services\\WalletServiceTest::it_fails_transaction":0.006}} \ No newline at end of file +{"version":2,"defects":{"Tests\\Feature\\Api\\PricingControllerTest::it_can_calculate_pricing_with_valid_data":5,"Tests\\Feature\\Api\\PricingControllerTest::it_returns_validation_errors_for_invalid_data":7,"Tests\\Feature\\Services\\PriceCalculatorServiceTest::it_calculates_price_correctly_for_standard_package":8,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_returns_active_discount_codes":8,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_validates_discount_code_successfully":8,"Tests\\Feature\\Api\\PaymentControllerTest::it_completes_mock_payment_successfully":7,"Tests\\Feature\\Services\\WalletServiceTest::it_creates_deposit_transaction":8,"Tests\\Feature\\Services\\WalletServiceTest::it_completes_deposit_and_updates_balance":8,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_deposit":8,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_withdrawal":8,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_withdrawal_when_balance_is_insufficient":7,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_order_payment":8,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_order_payment_when_balance_is_insufficient":7,"Tests\\Feature\\Services\\WalletServiceTest::it_fails_transaction":8},"times":{"Tests\\Feature\\Api\\PricingControllerTest::it_can_calculate_pricing_with_valid_data":0.056,"Tests\\Feature\\Api\\PricingControllerTest::it_returns_validation_errors_for_invalid_data":0.052,"Tests\\Feature\\Services\\PriceCalculatorServiceTest::it_calculates_price_correctly_for_standard_package":0.011,"Tests\\Unit\\ExampleTest::test_that_true_is_true":0.008,"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":0.06,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_returns_active_discount_codes":0.09,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_validates_discount_code_successfully":0.055,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_invalid_discount_code":0.047,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_expired_discount_code":0.05,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_code_below_minimum_order_amount":0.048,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_calculates_fixed_discount_correctly":0.047,"Tests\\Feature\\Api\\PaymentControllerTest::it_redirects_to_gateway_for_payment":0.068,"Tests\\Feature\\Api\\PaymentControllerTest::it_validates_minimum_deposit_amount":0.051,"Tests\\Feature\\Api\\PaymentControllerTest::it_prevents_payment_for_frozen_wallet":0.05,"Tests\\Feature\\Api\\PaymentControllerTest::it_completes_mock_payment_successfully":0.072,"Tests\\Feature\\Api\\PaymentControllerTest::it_checks_transaction_status":0.052,"Tests\\Feature\\Services\\WalletServiceTest::it_creates_deposit_transaction":0.004,"Tests\\Feature\\Services\\WalletServiceTest::it_completes_deposit_and_updates_balance":0.009,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_deposit":0.003,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_withdrawal":0.008,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_withdrawal_when_balance_is_insufficient":0.003,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_order_payment":0.003,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_order_payment_when_balance_is_insufficient":0.002,"Tests\\Feature\\Services\\WalletServiceTest::it_fails_transaction":0.022}} \ No newline at end of file diff --git a/04_Laravel/app/Filament/Pages/PriceTestPage.php b/04_Laravel/app/Filament/Pages/PriceTestPage.php index 861dc96..f432570 100644 --- a/04_Laravel/app/Filament/Pages/PriceTestPage.php +++ b/04_Laravel/app/Filament/Pages/PriceTestPage.php @@ -18,7 +18,8 @@ class PriceTestPage extends Page protected static ?string $navigationIcon = 'heroicon-o-calculator'; protected static string $view = 'filament.pages.price-test-page'; protected static ?string $navigationLabel = 'تست محاسبه قیمت'; - protected static ?int $navigationSort = 101; + protected static ?int $navigationSort = 999; + protected static bool $shouldRegisterNavigation = false; public ?array $data = []; public ?array $result = null; diff --git a/04_Laravel/app/Filament/Resources/CountryResource.php b/04_Laravel/app/Filament/Resources/CountryResource.php index 3e472fa..16f624c 100644 --- a/04_Laravel/app/Filament/Resources/CountryResource.php +++ b/04_Laravel/app/Filament/Resources/CountryResource.php @@ -18,6 +18,7 @@ class CountryResource extends Resource protected static ?string $navigationLabel = 'کشورها'; protected static ?string $navigationGroup = 'تنظیمات'; + protected static ?int $navigationSort = 2; public static function form(Form $form): Form { diff --git a/04_Laravel/app/Filament/Resources/DiscountCodeResource.php b/04_Laravel/app/Filament/Resources/DiscountCodeResource.php index d95cfb6..cd93ec0 100644 --- a/04_Laravel/app/Filament/Resources/DiscountCodeResource.php +++ b/04_Laravel/app/Filament/Resources/DiscountCodeResource.php @@ -18,7 +18,7 @@ class DiscountCodeResource extends Resource protected static ?string $navigationLabel = 'کدهای تخفیف'; protected static ?string $navigationGroup = 'مالی'; - protected static ?int $navigationSort = 1; + protected static ?int $navigationSort = 4; public static function form(Form $form): Form { diff --git a/04_Laravel/app/Filament/Resources/PaymentResource.php b/04_Laravel/app/Filament/Resources/PaymentResource.php index a8b0cc0..b63d214 100644 --- a/04_Laravel/app/Filament/Resources/PaymentResource.php +++ b/04_Laravel/app/Filament/Resources/PaymentResource.php @@ -18,7 +18,7 @@ class PaymentResource extends Resource protected static ?string $navigationLabel = 'پرداخت‌ها'; protected static ?string $navigationGroup = 'مالی'; - protected static ?int $navigationSort = 4; + protected static ?int $navigationSort = 3; public static function form(Form $form): Form { diff --git a/04_Laravel/app/Filament/Resources/ShipmentItemResource.php b/04_Laravel/app/Filament/Resources/ShipmentItemResource.php index fd3d674..ad9a21f 100644 --- a/04_Laravel/app/Filament/Resources/ShipmentItemResource.php +++ b/04_Laravel/app/Filament/Resources/ShipmentItemResource.php @@ -18,6 +18,7 @@ class ShipmentItemResource extends Resource protected static ?string $navigationLabel = 'اقلام مرسوله'; protected static ?string $navigationGroup = 'عملیات'; + protected static ?int $navigationSort = 2; public static function form(Form $form): Form { diff --git a/04_Laravel/app/Filament/Resources/ShipmentResource.php b/04_Laravel/app/Filament/Resources/ShipmentResource.php index c2c3d46..106e6d4 100644 --- a/04_Laravel/app/Filament/Resources/ShipmentResource.php +++ b/04_Laravel/app/Filament/Resources/ShipmentResource.php @@ -18,6 +18,7 @@ class ShipmentResource extends Resource protected static ?string $navigationLabel = 'مرسولات'; protected static ?string $navigationGroup = 'عملیات'; + protected static ?int $navigationSort = 1; public static function form(Form $form): Form { diff --git a/04_Laravel/app/Filament/Resources/ShippingRateResource.php b/04_Laravel/app/Filament/Resources/ShippingRateResource.php index a45db02..12abed0 100644 --- a/04_Laravel/app/Filament/Resources/ShippingRateResource.php +++ b/04_Laravel/app/Filament/Resources/ShippingRateResource.php @@ -18,6 +18,7 @@ class ShippingRateResource extends Resource protected static ?string $navigationLabel = 'نرخ‌های حمل'; protected static ?string $navigationGroup = 'تنظیمات'; + protected static ?int $navigationSort = 3; public static function form(Form $form): Form { diff --git a/04_Laravel/app/Filament/Resources/WalletResource.php b/04_Laravel/app/Filament/Resources/WalletResource.php index 486791c..0de454e 100644 --- a/04_Laravel/app/Filament/Resources/WalletResource.php +++ b/04_Laravel/app/Filament/Resources/WalletResource.php @@ -19,7 +19,7 @@ class WalletResource extends Resource protected static ?string $navigationIcon = 'heroicon-o-wallet'; protected static ?string $navigationLabel = 'کیف پول کاربران'; protected static ?string $navigationGroup = 'مالی'; - protected static ?int $navigationSort = 2; + protected static ?int $navigationSort = 1; public static function form(Form $form): Form { diff --git a/04_Laravel/app/Filament/Resources/WalletTransactionResource.php b/04_Laravel/app/Filament/Resources/WalletTransactionResource.php index b57fa6f..2a95b89 100644 --- a/04_Laravel/app/Filament/Resources/WalletTransactionResource.php +++ b/04_Laravel/app/Filament/Resources/WalletTransactionResource.php @@ -19,7 +19,7 @@ class WalletTransactionResource extends Resource protected static ?string $navigationIcon = 'heroicon-o-arrows-right-left'; protected static ?string $navigationLabel = 'تراکنش‌ها'; protected static ?string $navigationGroup = 'مالی'; - protected static ?int $navigationSort = 3; + protected static ?int $navigationSort = 2; public static function form(Form $form): Form { diff --git a/04_Laravel/app/Providers/Filament/AdminPanelProvider.php b/04_Laravel/app/Providers/Filament/AdminPanelProvider.php index 3686737..9801737 100644 --- a/04_Laravel/app/Providers/Filament/AdminPanelProvider.php +++ b/04_Laravel/app/Providers/Filament/AdminPanelProvider.php @@ -40,6 +40,8 @@ class AdminPanelProvider extends PanelProvider ]) ->authMiddleware([ Authenticate::class, - ]); + ]) + ->sidebarWidth('18rem') + ->maxContentWidth('xl'); } } diff --git a/04_Laravel/resources/css/filament.css b/04_Laravel/resources/css/filament.css new file mode 100644 index 0000000..fc9b53a --- /dev/null +++ b/04_Laravel/resources/css/filament.css @@ -0,0 +1,287 @@ +@import 'tailwindcss'; + +/* Custom IFNEX Filament Theme */ + +/* Sidebar Styling */ +.fi-sidebar { + background: linear-gradient(180deg, #1a1a2e 0%, #16213e 100%) !important; + border-left: 1px solid rgba(245, 158, 11, 0.2) !important; +} + +.fi-sidebar-header { + background: transparent !important; + border-bottom: 1px solid rgba(245, 158, 11, 0.15) !important; + padding: 1.25rem !important; +} + +.fi-sidebar-nav { + padding: 0.75rem !important; +} + +/* Navigation Groups */ +.fi-sidebar-nav-group { + margin-bottom: 0.5rem !important; + border-radius: 0.5rem !important; + overflow: hidden !important; +} + +.fi-sidebar-nav-group-header { + background: rgba(245, 158, 11, 0.08) !important; + border-bottom: 1px solid rgba(245, 158, 11, 0.1) !important; + transition: all 0.2s ease !important; +} + +.fi-sidebar-nav-group-header:hover { + background: rgba(245, 158, 11, 0.15) !important; +} + +.fi-sidebar-nav-group-item { + padding: 0.5rem 0.75rem !important; + font-weight: 500 !important; + color: rgba(255, 255, 255, 0.7) !important; + transition: all 0.2s ease !important; +} + +.fi-sidebar-nav-group-item:hover { + color: #fbbf24 !important; +} + +/* Navigation Items */ +.fi-sidebar-nav-item { + margin: 0.15rem 0 !important; + border-radius: 0.5rem !important; + transition: all 0.2s ease !important; + position: relative !important; + overflow: hidden !important; +} + +.fi-sidebar-nav-item::before { + content: '' !important; + position: absolute !important; + right: 0 !important; + top: 50% !important; + transform: translateY(-50%) !important; + width: 3px !important; + height: 0 !important; + background: #fbbf24 !important; + border-radius: 3px 0 0 3px !important; + transition: height 0.2s ease !important; +} + +.fi-sidebar-nav-item:hover::before, +.fi-sidebar-nav-item.active::before { + height: 60% !important; +} + +.fi-sidebar-nav-item:hover { + background: rgba(245, 158, 11, 0.1) !important; +} + +.fi-sidebar-nav-item.active { + background: rgba(245, 158, 11, 0.15) !important; + box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.2) !important; +} + +.fi-sidebar-nav-item.active .fi-sidebar-nav-item-label { + color: #fbbf24 !important; + font-weight: 600 !important; +} + +/* Icons */ +.fi-sidebar-nav-item-icon { + color: rgba(255, 255, 255, 0.6) !important; + transition: color 0.2s ease !important; +} + +.fi-sidebar-nav-item:hover .fi-sidebar-nav-item-icon, +.fi-sidebar-nav-item.active .fi-sidebar-nav-item-icon { + color: #fbbf24 !important; +} + +/* Labels */ +.fi-sidebar-nav-item-label { + color: rgba(255, 255, 255, 0.85) !important; + font-size: 0.875rem !important; + transition: color 0.2s ease !important; +} + +.fi-sidebar-nav-group-item { + color: rgba(255, 255, 255, 0.5) !important; + font-size: 0.75rem !important; + text-transform: uppercase !important; + letter-spacing: 0.05em !important; +} + +/* Badges */ +.fi-badge { + font-weight: 600 !important; + border-radius: 9999px !important; + font-size: 0.75rem !important; + padding: 0.125rem 0.5rem !important; +} + +/* Cards and Panels */ +.fi-card { + border-radius: 0.75rem !important; + border: 1px solid #e5e7eb !important; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important; + transition: all 0.2s ease !important; +} + +.fi-card:hover { + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1) !important; +} + +/* Buttons */ +.fi-btn { + border-radius: 0.5rem !important; + font-weight: 500 !important; + transition: all 0.2s ease !important; +} + +.fi-btn-primary { + background: #f59e0b !important; + border-color: #f59e0b !important; +} + +.fi-btn-primary:hover { + background: #d97706 !important; + border-color: #d97706 !important; + transform: translateY(-1px) !important; + box-shadow: 0 4px 6px -1px rgba(245, 158, 11, 0.3) !important; +} + +/* Tables */ +.fi-ta-table { + border-radius: 0.75rem !important; + overflow: hidden !important; +} + +.fi-ta-header-cell { + background: #f9fafb !important; + font-weight: 600 !important; + color: #374151 !important; + font-size: 0.75rem !important; + text-transform: uppercase !important; + letter-spacing: 0.05em !important; +} + +.fi-ta-row { + transition: background-color 0.15s ease !important; +} + +.fi-ta-row:hover { + background-color: #fffbeb !important; +} + +/* Forms */ +.fi-input { + border-radius: 0.5rem !important; + border-color: #d1d5db !important; + transition: all 0.2s ease !important; +} + +.fi-input:focus { + border-color: #fbbf24 !important; + box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1) !important; +} + +.fi-select { + border-radius: 0.5rem !important; +} + +/* Widgets */ +.fi-wi-stats-overview { + gap: 1rem !important; +} + +.fi-wi-stats-overview-card { + border-radius: 0.75rem !important; + border: 1px solid #e5e7eb !important; + transition: all 0.2s ease !important; +} + +.fi-wi-stats-overview-card:hover { + transform: translateY(-2px) !important; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1) !important; +} + +/* Dashboard */ +.fi-page-header { + border-bottom: 2px solid #fbbf24 !important; + margin-bottom: 1.5rem !important; + padding-bottom: 1rem !important; +} + +/* Top Navigation */ +.fi-topbar { + border-bottom: 1px solid #f3f4f6 !important; + background: #ffffff !important; +} + +/* Notifications */ +.fi-notification { + border-radius: 0.75rem !important; + border-right: 4px solid #fbbf24 !important; +} + +/* Modals */ +.fi-modal { + border-radius: 0.75rem !important; + overflow: hidden !important; +} + +/* Dropdowns */ +.fi-dropdown { + border-radius: 0.5rem !important; + border: 1px solid #e5e7eb !important; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1) !important; +} + +/* Tabs */ +.fi-tabs { + border-bottom: 2px solid #f3f4f6 !important; +} + +.fi-tab { + border-bottom: 2px solid transparent !important; + margin-bottom: -2px !important; + transition: all 0.2s ease !important; +} + +.fi-tab:hover { + border-bottom-color: #fbbf24 !important; + color: #d97706 !important; +} + +.fi-tab.active { + border-bottom-color: #fbbf24 !important; + color: #d97706 !important; + font-weight: 600 !important; +} + +/* Scrollbar */ +::-webkit-scrollbar { + width: 8px !important; + height: 8px !important; +} + +::-webkit-scrollbar-track { + background: #f1f5f9 !important; +} + +::-webkit-scrollbar-thumb { + background: #cbd5e1 !important; + border-radius: 4px !important; +} + +::-webkit-scrollbar-thumb:hover { + background: #94a3b8 !important; +} + +/* Dark mode adjustments */ +@media (prefers-color-scheme: dark) { + .fi-sidebar { + background: linear-gradient(180deg, #0f172a 0%, #1e293b 100%) !important; + } +}