Andrew Wallo пре 5 месеци
родитељ
комит
331313305c

+ 44
- 7
app/Filament/Company/Pages/Accounting/Transactions.php Прегледај датотеку

8
 use App\Enums\Accounting\TransactionType;
8
 use App\Enums\Accounting\TransactionType;
9
 use App\Facades\Accounting;
9
 use App\Facades\Accounting;
10
 use App\Filament\Company\Pages\Service\ConnectedAccount;
10
 use App\Filament\Company\Pages\Service\ConnectedAccount;
11
+use App\Filament\Forms\Components\CustomTableRepeater;
11
 use App\Filament\Forms\Components\DateRangeSelect;
12
 use App\Filament\Forms\Components\DateRangeSelect;
12
-use App\Filament\Forms\Components\JournalEntryRepeater;
13
 use App\Filament\Tables\Actions\ReplicateBulkAction;
13
 use App\Filament\Tables\Actions\ReplicateBulkAction;
14
 use App\Models\Accounting\Account;
14
 use App\Models\Accounting\Account;
15
 use App\Models\Accounting\JournalEntry;
15
 use App\Models\Accounting\JournalEntry;
538
             ]);
538
             ]);
539
     }
539
     }
540
 
540
 
541
-    protected function getJournalEntriesTableRepeater(): JournalEntryRepeater
541
+    protected function getJournalEntriesTableRepeater(): CustomTableRepeater
542
     {
542
     {
543
-        return JournalEntryRepeater::make('journalEntries')
543
+        return CustomTableRepeater::make('journalEntries')
544
             ->relationship('journalEntries')
544
             ->relationship('journalEntries')
545
             ->hiddenLabel()
545
             ->hiddenLabel()
546
             ->columns(4)
546
             ->columns(4)
547
             ->headers($this->getJournalEntriesTableRepeaterHeaders())
547
             ->headers($this->getJournalEntriesTableRepeaterHeaders())
548
             ->schema($this->getJournalEntriesTableRepeaterSchema())
548
             ->schema($this->getJournalEntriesTableRepeaterSchema())
549
-            ->streamlined()
550
-            ->deletable(fn (JournalEntryRepeater $repeater) => $repeater->getItemsCount() > 2)
549
+            ->deletable(fn (CustomTableRepeater $repeater) => $repeater->getItemsCount() > 2)
551
             ->deleteAction(function (Forms\Components\Actions\Action $action) {
550
             ->deleteAction(function (Forms\Components\Actions\Action $action) {
552
                 return $action
551
                 return $action
553
-                    ->action(function (array $arguments, JournalEntryRepeater $component): void {
552
+                    ->action(function (array $arguments, CustomTableRepeater $component): void {
554
                         $items = $component->getState();
553
                         $items = $component->getState();
555
 
554
 
556
                         $amount = $items[$arguments['item']]['amount'];
555
                         $amount = $items[$arguments['item']]['amount'];
565
                         $component->callAfterStateUpdated();
564
                         $component->callAfterStateUpdated();
566
                     });
565
                     });
567
             })
566
             })
567
+            ->rules([
568
+                function () {
569
+                    return function (string $attribute, $value, \Closure $fail) {
570
+                        if (empty($value) || ! is_array($value)) {
571
+                            $fail('Journal entries are required.');
572
+
573
+                            return;
574
+                        }
575
+
576
+                        $hasDebit = false;
577
+                        $hasCredit = false;
578
+
579
+                        foreach ($value as $entry) {
580
+                            if (! isset($entry['type'])) {
581
+                                continue;
582
+                            }
583
+
584
+                            if (JournalEntryType::parse($entry['type'])->isDebit()) {
585
+                                $hasDebit = true;
586
+                            } elseif (JournalEntryType::parse($entry['type'])->isCredit()) {
587
+                                $hasCredit = true;
588
+                            }
589
+
590
+                            if ($hasDebit && $hasCredit) {
591
+                                break;
592
+                            }
593
+                        }
594
+
595
+                        if (! $hasDebit) {
596
+                            $fail('At least one debit entry is required.');
597
+                        }
598
+
599
+                        if (! $hasCredit) {
600
+                            $fail('At least one credit entry is required.');
601
+                        }
602
+                    };
603
+                },
604
+            ])
568
             ->minItems(2)
605
             ->minItems(2)
569
             ->defaultItems(2)
606
             ->defaultItems(2)
570
             ->addable(false)
607
             ->addable(false)
634
             ->color($type->isDebit() ? 'primary' : 'gray')
671
             ->color($type->isDebit() ? 'primary' : 'gray')
635
             ->iconSize(IconSize::Small)
672
             ->iconSize(IconSize::Small)
636
             ->iconPosition(IconPosition::Before)
673
             ->iconPosition(IconPosition::Before)
637
-            ->action(function (JournalEntryRepeater $component) use ($type) {
674
+            ->action(function (CustomTableRepeater $component) use ($type) {
638
                 $state = $component->getState();
675
                 $state = $component->getState();
639
                 $newUuid = (string) Str::uuid();
676
                 $newUuid = (string) Str::uuid();
640
                 $state[$newUuid] = $this->defaultEntry($type);
677
                 $state[$newUuid] = $this->defaultEntry($type);

+ 21
- 0
app/Filament/Forms/Components/CustomTableRepeater.php Прегледај датотеку

5
 use Awcodes\TableRepeater\Components\TableRepeater;
5
 use Awcodes\TableRepeater\Components\TableRepeater;
6
 use Closure;
6
 use Closure;
7
 use Filament\Forms\Components\Actions\Action;
7
 use Filament\Forms\Components\Actions\Action;
8
+use Illuminate\Contracts\Support\Htmlable;
9
+use Illuminate\Contracts\View\View;
8
 
10
 
9
 class CustomTableRepeater extends TableRepeater
11
 class CustomTableRepeater extends TableRepeater
10
 {
12
 {
12
 
14
 
13
     protected bool | Closure $reorderAtStart = false;
15
     protected bool | Closure $reorderAtStart = false;
14
 
16
 
17
+    protected View | Htmlable | Closure | null $footerItem = null;
18
+
15
     /**
19
     /**
16
      * @var array<string> | Closure | null
20
      * @var array<string> | Closure | null
17
      */
21
      */
48
         return $this->evaluate($this->reorderAtStart) && $this->isReorderable();
52
         return $this->evaluate($this->reorderAtStart) && $this->isReorderable();
49
     }
53
     }
50
 
54
 
55
+    public function footerItem(View | Htmlable | Closure | null $footer = null): static
56
+    {
57
+        $this->footerItem = $footer;
58
+
59
+        return $this;
60
+    }
61
+
62
+    public function getFooterItem(): View | Htmlable | null
63
+    {
64
+        return $this->evaluate($this->footerItem);
65
+    }
66
+
67
+    public function hasFooterItem(): bool
68
+    {
69
+        return $this->footerItem !== null;
70
+    }
71
+
51
     /**
72
     /**
52
      * @param  array<string> | Closure | null  $attributes
73
      * @param  array<string> | Closure | null  $attributes
53
      */
74
      */

+ 25
- 22
resources/views/filament/forms/components/custom-table-repeater.blade.php Прегледај датотеку

222
             </div>
222
             </div>
223
         @endif
223
         @endif
224
 
224
 
225
-        @if ($addAction->isVisible() || filled($visibleExtraActions))
226
-            <ul
227
-                @class([
228
-                    'relative flex gap-4',
229
-                    match ($getAddActionAlignment()) {
230
-                        Alignment::Start, Alignment::Left => 'justify-start',
231
-                        Alignment::End, Alignment::Right => 'justify-end',
232
-                        default =>  'justify-center',
233
-                    },
234
-                ])
235
-            >
236
-                @if ($addAction->isVisible())
237
-                    <li>
238
-                        {{ $addAction }}
239
-                    </li>
225
+        @if ($addAction->isVisible() || filled($visibleExtraActions) || $hasFooterItem())
226
+            <div class="flex justify-between items-start">
227
+                <!-- Actions grouped to the left -->
228
+                @if ($addAction->isVisible() || filled($visibleExtraActions))
229
+                    <ul class="flex gap-4">
230
+                        @if ($addAction->isVisible())
231
+                            <li>
232
+                                {{ $addAction }}
233
+                            </li>
234
+                        @endif
235
+                        @if (filled($visibleExtraActions))
236
+                            @foreach ($visibleExtraActions as $extraAction)
237
+                                <li>
238
+                                    {{ $extraAction }}
239
+                                </li>
240
+                            @endforeach
241
+                        @endif
242
+                    </ul>
240
                 @endif
243
                 @endif
241
-                @if (filled($visibleExtraActions))
242
-                    @foreach ($visibleExtraActions as $extraAction)
243
-                        <li>
244
-                            {{ ($extraAction) }}
245
-                        </li>
246
-                    @endforeach
244
+
245
+                <!-- Container for Footer Item to the right -->
246
+                @if($hasFooterItem())
247
+                    <div>
248
+                        {{ $getFooterItem() }}
249
+                    </div>
247
                 @endif
250
                 @endif
248
-            </ul>
251
+            </div>
249
         @endif
252
         @endif
250
     </div>
253
     </div>
251
 </x-dynamic-component>
254
 </x-dynamic-component>

Loading…
Откажи
Сачувај