Andrew Wallo 1 年之前
父節點
當前提交
dc95d167b8

+ 126
- 2
app/Filament/Company/Pages/Concerns/HasDeferredFiltersForm.php 查看文件

2
 
2
 
3
 namespace App\Filament\Company\Pages\Concerns;
3
 namespace App\Filament\Company\Pages\Concerns;
4
 
4
 
5
+use Filament\Actions\Action;
6
+use Filament\Forms\Components\DatePicker;
7
+use Filament\Forms\Form;
8
+use Illuminate\Support\Arr;
5
 use Illuminate\Support\Carbon;
9
 use Illuminate\Support\Carbon;
6
 
10
 
7
 trait HasDeferredFiltersForm
11
 trait HasDeferredFiltersForm
8
 {
12
 {
13
+    /**
14
+     * @var array<string, mixed> | null
15
+     */
16
+    public ?array $filters = null;
17
+
18
+    /**
19
+     * @var array<string, mixed> | null
20
+     */
21
+    public ?array $deferredFilters = null;
22
+
23
+    public function mountHasDeferredFiltersForm(): void
24
+    {
25
+        $this->initializeDefaultFilters();
26
+
27
+        $this->initializeFilters();
28
+    }
29
+
30
+    protected function initializeDefaultFilters(): void
31
+    {
32
+        //
33
+    }
34
+
35
+    public function initializeFilters(): void
36
+    {
37
+        if (! count($this->filters ?? [])) {
38
+            $this->filters = null;
39
+        }
40
+
41
+        $this->getFiltersForm()->fill($this->filters);
42
+    }
43
+
44
+    protected function getHasDeferredFiltersFormForms(): array
45
+    {
46
+        return [
47
+            'filtersForm' => $this->getFiltersForm(),
48
+        ];
49
+    }
50
+
51
+    public function filtersForm(Form $form): Form
52
+    {
53
+        return $form;
54
+    }
55
+
56
+    public function getFiltersForm(): Form
57
+    {
58
+        return $this->filtersForm($this->makeForm()
59
+            ->statePath('deferredFilters'));
60
+    }
61
+
62
+    public function updatedFilters(): void
63
+    {
64
+        $this->deferredFilters = $this->filters;
65
+
66
+        $this->handleFilterUpdates();
67
+    }
68
+
69
+    protected function isValidDate($date): bool
70
+    {
71
+        return strtotime($date) !== false;
72
+    }
73
+
74
+    protected function handleFilterUpdates(): void
75
+    {
76
+        //
77
+    }
78
+
79
+    public function applyFilters(): void
80
+    {
81
+        $this->filters = $this->deferredFilters;
82
+
83
+        $this->handleFilterUpdates();
84
+
85
+        $this->loadReportData();
86
+    }
87
+
88
+    public function applyFiltersAction(): Action
89
+    {
90
+        return Action::make('applyFilters')
91
+            ->label('Update Report')
92
+            ->action('applyFilters')
93
+            ->keyBindings(['mod+s'])
94
+            ->button();
95
+    }
96
+
97
+    public function getFilterState(string $name): mixed
98
+    {
99
+        return Arr::get($this->filters, $name);
100
+    }
101
+
102
+    public function setFilterState(string $name, mixed $value): void
103
+    {
104
+        Arr::set($this->filters, $name, $value);
105
+    }
106
+
107
+    public function getDeferredFilterState(string $name): mixed
108
+    {
109
+        return Arr::get($this->deferredFilters, $name);
110
+    }
111
+
112
+    public function setDeferredFilterState(string $name, mixed $value): void
113
+    {
114
+        Arr::set($this->deferredFilters, $name, $value);
115
+    }
116
+
117
+    protected function convertDatesToDateTimeString(array $filters): array
118
+    {
119
+        if (isset($filters['startDate'])) {
120
+            $filters['startDate'] = Carbon::parse($filters['startDate'])->startOfDay()->toDateTimeString();
121
+        }
122
+
123
+        if (isset($filters['endDate'])) {
124
+            $filters['endDate'] = Carbon::parse($filters['endDate'])->endOfDay()->toDateTimeString();
125
+        }
126
+
127
+        return $filters;
128
+    }
129
+
9
     protected function queryStringHasDeferredFiltersForm(): array
130
     protected function queryStringHasDeferredFiltersForm(): array
10
     {
131
     {
11
         // Get the filter keys dynamically from the filters form
132
         // Get the filter keys dynamically from the filters form
49
     protected function excludeQueryStrings(): array
170
     protected function excludeQueryStrings(): array
50
     {
171
     {
51
         return [
172
         return [
52
-            'dateRange', // Example: dateRange should not have 'as' and 'keep'
173
+            'dateRange',
53
         ];
174
         ];
54
     }
175
     }
55
 
176
 
56
     public function dehydrateHasDeferredFiltersForm(): void
177
     public function dehydrateHasDeferredFiltersForm(): void
57
     {
178
     {
179
+        $flatFields = $this->getFiltersForm()->getFlatFields();
180
+
58
         foreach ($this->filters as $key => $value) {
181
         foreach ($this->filters as $key => $value) {
59
-            if ($this->isDateFilter($value)) {
182
+            if (isset($flatFields[$key]) && $flatFields[$key] instanceof DatePicker) {
183
+                // TODO: Submit a PR to Filament to address DatePicker being dehydrated as a datetime string in filters
60
                 $this->filters[$key] = Carbon::parse($value)->toDateString();
184
                 $this->filters[$key] = Carbon::parse($value)->toDateString();
61
             }
185
             }
62
         }
186
         }

+ 39
- 0
app/Filament/Company/Pages/Concerns/HasToggleTableColumnForm.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Company\Pages\Concerns;
4
+
5
+use Filament\Actions\Action;
6
+use Filament\Forms\Form;
7
+use Filament\Support\Enums\ActionSize;
8
+use Filament\Support\Facades\FilamentIcon;
9
+
10
+trait HasToggleTableColumnForm
11
+{
12
+    protected function getHasToggleTableColumnFormForms(): array
13
+    {
14
+        return [
15
+            'toggleTableColumnForm' => $this->getToggleTableColumnForm(),
16
+        ];
17
+    }
18
+
19
+    public function getToggleTableColumnForm(): Form
20
+    {
21
+        return $this->toggleTableColumnForm($this->makeForm()
22
+            ->statePath('toggledTableColumns'));
23
+    }
24
+
25
+    public function toggleTableColumnForm(Form $form): Form
26
+    {
27
+        return $form;
28
+    }
29
+
30
+    public function toggleColumnsAction(): Action
31
+    {
32
+        return Action::make('toggleColumns')
33
+            ->label(__('filament-tables::table.actions.toggle_columns.label'))
34
+            ->iconButton()
35
+            ->size(ActionSize::Large)
36
+            ->icon(FilamentIcon::resolve('tables::actions.toggle-columns') ?? 'heroicon-m-view-columns')
37
+            ->color('gray');
38
+    }
39
+}

+ 43
- 0
app/Filament/Company/Pages/Dashboard.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Company\Pages;
4
+
5
+use Filament\Forms\Components\DatePicker;
6
+use Filament\Forms\Components\Section;
7
+use Filament\Forms\Form;
8
+use Filament\Forms\Set;
9
+use Filament\Pages\Dashboard\Actions\FilterAction;
10
+use Filament\Pages\Dashboard\Concerns\HasFiltersAction;
11
+
12
+class Dashboard extends \Filament\Pages\Dashboard
13
+{
14
+    use HasFiltersAction;
15
+
16
+    //    public function filtersForm(Form $form): Form
17
+    //    {
18
+    //        return $form
19
+    //            ->schema([
20
+    //                Section::make()
21
+    //                    ->schema([
22
+    //                        DatePicker::make('startDate'),
23
+    //                        DatePicker::make('endDate'),
24
+    //                        // ...
25
+    //                    ])
26
+    //                    ->columns(3),
27
+    //            ]);
28
+    //    }
29
+
30
+    protected function getHeaderActions(): array
31
+    {
32
+        return [
33
+            FilterAction::make()
34
+                ->form([
35
+                    DatePicker::make('startDate')
36
+                        ->live()
37
+                        ->afterStateUpdated(fn (Set $set) => $set('endDate', now()->toDateTimeString())),
38
+                    DatePicker::make('endDate'),
39
+                    // ...
40
+                ]),
41
+        ];
42
+    }
43
+}

+ 3
- 130
app/Filament/Company/Pages/Reports/BaseReportPage.php 查看文件

5
 use App\Contracts\ExportableReport;
5
 use App\Contracts\ExportableReport;
6
 use App\DTO\ReportDTO;
6
 use App\DTO\ReportDTO;
7
 use App\Filament\Company\Pages\Concerns\HasDeferredFiltersForm;
7
 use App\Filament\Company\Pages\Concerns\HasDeferredFiltersForm;
8
+use App\Filament\Company\Pages\Concerns\HasToggleTableColumnForm;
8
 use App\Filament\Forms\Components\DateRangeSelect;
9
 use App\Filament\Forms\Components\DateRangeSelect;
9
 use App\Models\Company;
10
 use App\Models\Company;
10
 use App\Services\DateRangeService;
11
 use App\Services\DateRangeService;
17
 use Filament\Forms\Form;
18
 use Filament\Forms\Form;
18
 use Filament\Forms\Set;
19
 use Filament\Forms\Set;
19
 use Filament\Pages\Page;
20
 use Filament\Pages\Page;
20
-use Filament\Support\Enums\ActionSize;
21
 use Filament\Support\Enums\IconPosition;
21
 use Filament\Support\Enums\IconPosition;
22
 use Filament\Support\Enums\IconSize;
22
 use Filament\Support\Enums\IconSize;
23
-use Filament\Support\Facades\FilamentIcon;
24
-use Illuminate\Support\Arr;
25
 use Illuminate\Support\Carbon;
23
 use Illuminate\Support\Carbon;
26
 use Livewire\Attributes\Computed;
24
 use Livewire\Attributes\Computed;
27
 use Livewire\Attributes\Session;
25
 use Livewire\Attributes\Session;
30
 abstract class BaseReportPage extends Page
28
 abstract class BaseReportPage extends Page
31
 {
29
 {
32
     use HasDeferredFiltersForm;
30
     use HasDeferredFiltersForm;
33
-
34
-    /**
35
-     * @var array<string, mixed> | null
36
-     */
37
-    public ?array $filters = null;
38
-
39
-    /**
40
-     * @var array<string, mixed> | null
41
-     */
42
-    public ?array $deferredFilters = null;
31
+    use HasToggleTableColumnForm;
43
 
32
 
44
     public string $fiscalYearStartDate;
33
     public string $fiscalYearStartDate;
45
 
34
 
71
 
60
 
72
         $this->loadDefaultDateRange();
61
         $this->loadDefaultDateRange();
73
 
62
 
74
-        $this->initializeDefaultFilters();
75
-
76
-        $this->initializeFilters();
77
-
78
         $this->loadDefaultTableColumnToggleState();
63
         $this->loadDefaultTableColumnToggleState();
79
     }
64
     }
80
 
65
 
81
-    protected function initializeDefaultFilters(): void
82
-    {
83
-        //
84
-    }
85
-
86
-    public function initializeFilters(): void
87
-    {
88
-        if (! count($this->filters ?? [])) {
89
-            $this->filters = null;
90
-        }
91
-
92
-        $this->getFiltersForm()->fill($this->filters);
93
-    }
94
-
95
-    protected function convertDatesToDateTimeString(array $filters): array
96
-    {
97
-        if (isset($filters['startDate'])) {
98
-            $filters['startDate'] = Carbon::parse($filters['startDate'])->startOfDay()->toDateTimeString();
99
-        }
100
-
101
-        if (isset($filters['endDate'])) {
102
-            $filters['endDate'] = Carbon::parse($filters['endDate'])->endOfDay()->toDateTimeString();
103
-        }
104
-
105
-        return $filters;
106
-    }
107
-
108
-    protected function getForms(): array
109
-    {
110
-        return [
111
-            'toggleTableColumnForm',
112
-            'filtersForm' => $this->getFiltersForm(),
113
-        ];
114
-    }
115
-
116
-    public function filtersForm(Form $form): Form
117
-    {
118
-        return $form;
119
-    }
120
-
121
-    public function getFiltersForm(): Form
122
-    {
123
-        return $this->filtersForm($this->makeForm()
124
-            ->statePath('deferredFilters'));
125
-    }
126
-
127
-    public function updatedFilters(): void
128
-    {
129
-        $this->deferredFilters = $this->filters;
130
-
131
-        $this->handleFilterUpdates();
132
-    }
133
-
134
-    protected function isValidDate($date): bool
135
-    {
136
-        return strtotime($date) !== false;
137
-    }
138
-
139
-    protected function handleFilterUpdates(): void
140
-    {
141
-        //
142
-    }
143
-
144
-    public function applyFilters(): void
145
-    {
146
-        $this->filters = $this->deferredFilters;
147
-
148
-        $this->handleFilterUpdates();
149
-
150
-        $this->loadReportData();
151
-    }
152
-
153
-    public function getFiltersApplyAction(): Action
154
-    {
155
-        return Action::make('applyFilters')
156
-            ->label('Update Report')
157
-            ->action('applyFilters')
158
-            ->keyBindings(['mod+s'])
159
-            ->button();
160
-    }
161
-
162
-    public function getFilterState(string $name): mixed
163
-    {
164
-        return Arr::get($this->filters, $name);
165
-    }
166
-
167
-    public function setFilterState(string $name, mixed $value): void
168
-    {
169
-        Arr::set($this->filters, $name, $value);
170
-    }
171
-
172
-    public function getDeferredFilterState(string $name): mixed
173
-    {
174
-        return Arr::get($this->deferredFilters, $name);
175
-    }
176
-
177
-    public function setDeferredFilterState(string $name, mixed $value): void
178
-    {
179
-        Arr::set($this->deferredFilters, $name, $value);
180
-    }
181
-
182
     protected function initializeProperties(): void
66
     protected function initializeProperties(): void
183
     {
67
     {
184
         $this->company = auth()->user()->currentCompany;
68
         $this->company = auth()->user()->currentCompany;
275
         return Carbon::parse($this->getFilterState('endDate'))->endOfDay()->toDateTimeString();
159
         return Carbon::parse($this->getFilterState('endDate'))->endOfDay()->toDateTimeString();
276
     }
160
     }
277
 
161
 
278
-    public function toggleColumnsAction(): Action
279
-    {
280
-        return Action::make('toggleColumns')
281
-            ->label(__('filament-tables::table.actions.toggle_columns.label'))
282
-            ->iconButton()
283
-            ->size(ActionSize::Large)
284
-            ->icon(FilamentIcon::resolve('tables::actions.toggle-columns') ?? 'heroicon-m-view-columns')
285
-            ->color('gray');
286
-    }
287
-
288
     public function toggleTableColumnForm(Form $form): Form
162
     public function toggleTableColumnForm(Form $form): Form
289
     {
163
     {
290
         return $form
164
         return $form
291
-            ->schema($this->getTableColumnToggleFormSchema())
292
-            ->statePath('toggledTableColumns');
165
+            ->schema($this->getTableColumnToggleFormSchema());
293
     }
166
     }
294
 
167
 
295
     protected function hasToggleableColumns(): bool
168
     protected function hasToggleableColumns(): bool

+ 8
- 4
app/Listeners/ConfigureCompanyDefault.php 查看文件

71
         Tab::configureUsing(static function (Tab $tab) {
71
         Tab::configureUsing(static function (Tab $tab) {
72
             $label = $tab->getLabel();
72
             $label = $tab->getLabel();
73
 
73
 
74
-            $translatedLabel = translate($label);
74
+            if ($label) {
75
+                $translatedLabel = translate($label);
75
 
76
 
76
-            $tab->label(ucwords($translatedLabel));
77
+                $tab->label(ucwords($translatedLabel));
78
+            }
77
         }, isImportant: true);
79
         }, isImportant: true);
78
 
80
 
79
         Section::configureUsing(static function (Section $section): void {
81
         Section::configureUsing(static function (Section $section): void {
80
             $heading = $section->getHeading();
82
             $heading = $section->getHeading();
81
 
83
 
82
-            $translatedHeading = translate($heading);
84
+            if ($heading) {
85
+                $translatedHeading = translate($heading);
83
 
86
 
84
-            $section->heading(ucfirst($translatedHeading));
87
+                $section->heading(ucfirst($translatedHeading));
88
+            }
85
         }, isImportant: true);
89
         }, isImportant: true);
86
 
90
 
87
         ResourcesTab::configureUsing(static function (ResourcesTab $tab): void {
91
         ResourcesTab::configureUsing(static function (ResourcesTab $tab): void {

+ 1
- 4
app/Providers/FilamentCompaniesServiceProvider.php 查看文件

42
 use Filament\Http\Middleware\DispatchServingFilamentEvent;
42
 use Filament\Http\Middleware\DispatchServingFilamentEvent;
43
 use Filament\Navigation\NavigationBuilder;
43
 use Filament\Navigation\NavigationBuilder;
44
 use Filament\Navigation\NavigationGroup;
44
 use Filament\Navigation\NavigationGroup;
45
-use Filament\Pages;
46
 use Filament\Pages\Dashboard;
45
 use Filament\Pages\Dashboard;
47
 use Filament\Panel;
46
 use Filament\Panel;
48
 use Filament\PanelProvider;
47
 use Filament\PanelProvider;
148
             ->discoverResources(in: app_path('Filament/Company/Resources'), for: 'App\\Filament\\Company\\Resources')
147
             ->discoverResources(in: app_path('Filament/Company/Resources'), for: 'App\\Filament\\Company\\Resources')
149
             ->discoverPages(in: app_path('Filament/Company/Pages'), for: 'App\\Filament\\Company\\Pages')
148
             ->discoverPages(in: app_path('Filament/Company/Pages'), for: 'App\\Filament\\Company\\Pages')
150
             ->discoverClusters(in: app_path('Filament/Company/Clusters'), for: 'App\\Filament\\Company\\Clusters')
149
             ->discoverClusters(in: app_path('Filament/Company/Clusters'), for: 'App\\Filament\\Company\\Clusters')
151
-            ->pages([
152
-                Pages\Dashboard::class,
153
-            ])
150
+            ->pages([])
154
             ->authGuard('web')
151
             ->authGuard('web')
155
             ->discoverWidgets(in: app_path('Filament/Company/Widgets'), for: 'App\\Filament\\Company\\Widgets')
152
             ->discoverWidgets(in: app_path('Filament/Company/Widgets'), for: 'App\\Filament\\Company\\Widgets')
156
             ->widgets([
153
             ->widgets([

+ 7
- 4
resources/views/filament/company/pages/reports/income-statement.blade.php 查看文件

2
     <x-filament::section>
2
     <x-filament::section>
3
         <div class="flex flex-col md:flex-row items-start md:items-center justify-between gap-4 md:gap-8">
3
         <div class="flex flex-col md:flex-row items-start md:items-center justify-between gap-4 md:gap-8">
4
             <!-- Form Container -->
4
             <!-- Form Container -->
5
-            <div class="flex-grow">
6
-                {{ $this->getFiltersForm() }}
7
-            </div>
5
+            @if(method_exists($this, 'filtersForm'))
6
+                {{ $this->filtersForm }}
7
+            @endif
8
 
8
 
9
             <!-- Grouping Button and Column Toggle -->
9
             <!-- Grouping Button and Column Toggle -->
10
             <div class="flex flex-col md:flex-row items-start md:items-center gap-4 md:gap-8 flex-shrink-0">
10
             <div class="flex flex-col md:flex-row items-start md:items-center gap-4 md:gap-8 flex-shrink-0">
14
                         :trigger-action="$this->toggleColumnsAction"
14
                         :trigger-action="$this->toggleColumnsAction"
15
                     />
15
                     />
16
                 @endif
16
                 @endif
17
-                {{ $this->getFiltersApplyAction() }}
17
+            </div>
18
+
19
+            <div class="inline-flex items-center flex-shrink-0 min-w-[8.5rem] justify-end">
20
+                {{ $this->applyFiltersAction }}
18
             </div>
21
             </div>
19
         </div>
22
         </div>
20
     </x-filament::section>
23
     </x-filament::section>

Loading…
取消
儲存