Raz4r
Raz4r

Reputation: 19

Filament dispatching events from widget to another table widget - old state

I'm using filament in version 3 with php 8.4 and Laravel 11.

I have ReportDashboard Page with DepartmentFilter and Multiple Table widget's i will pick one.

In ReportDashboard i declare widgets:

protected function getHeaderWidgets(): array
{
    $departments = $this->getDepartments();

    return [
        DepartmentFilter::make(['departments' => $departments]),
        BrokersResults::make(['departments' => $departments]),
    ];
}

private function getDepartments(): array
{
    return Cache::remember('department-list', now()->addDay(), static fn() => User::query()->get();
}

In DepartmentFilter i have code like this:

<?php

namespace App\Filament\Resources\ReportResource\Widgets;

use Filament\Forms\Components\Select;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Form;
use Filament\Widgets\Widget;

class DepartmentFilter extends Widget implements HasForms
{
    use InteractsWithForms;

    protected static string $view = 'filament.widgets.filters';
    protected static ?int $sort = 1;
    public array $departments = [];
    public ?int $departmentId = null;

    protected int|string|array $columnSpan = [
        'xs' => 1,
        'md' => 2,
    ];

    public function form(Form $form): form
    {
        return $form
            ->schema(
                [
                    Select::make('department_id')
                        ->label(__('labels.department'))
                        ->selectablePlaceholder(false)
                        ->statePath('departmentId')
                        ->options($this->departments)
                        ->live()
                        ->afterStateUpdated(function (?string $state) {
                            ray(['departmentFilter', $state ?? array_key_first($this->departments)])->orange();
                            $this->dispatch(
                                'departmentChanged',
                                departmentId: $state ?? array_key_first($this->departments)
                            );
                        })
                        ->columnSpanFull()
                ]
            );
    }
}

And finally we have BrokersResults

<?php

namespace App\Filament\Resources\ReportResource\Widgets;

use App\Enums\ReportPeriodEnum;
use App\Interfaces\Repositories\ReportRepositoryInterface;
use App\Models\Process\Bank;
use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Carbon\CarbonPeriod;
use Filament\Forms\Components\Select;
use Filament\Forms\Get;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Table;
use Filament\Widgets\Concerns\InteractsWithPageFilters;
use Filament\Widgets\TableWidget as BaseWidget;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Livewire\Attributes\On;
use stdClass;

class BrokersResults extends BaseWidget
{
    use InteractsWithPageFilters;

    public array $departments = [] {
        set {
            $this->departments = $value;
            $this->departmentId ??= array_key_first($value);
            ray(['brokersResults-set', $this->departmentId])->purple();
        }
    }

    protected $listeners = ['departmentChanged' => '$refresh'];

    public function __construct(
        public ?int $departmentId = null
    ) {
    }

    #[On('departmentChanged')]
    public function departmentChanged(int $departmentId): void
    {
        ray(['brokersResults', $departmentId])->purple();
        $this->departmentId = $departmentId;
    }

    //- We use joins and custom grouping logic, so we need to override the recordKey.
    public function getTableRecordKey(Model $record): string
    {
        return $record->user_id;
    }

    public function table(Table $table): Table
    {
        return $table
            ->filters(
                [
                    Filter::make('results_period')
                        ->columnSpanFull()
                        ->resetState(null)
                        ->columns(3)
                        ->form([
                            Select::make('period')
                                ->label(__('labels.period'))
                                ->default(ReportPeriodEnum::YEARLY->value)
                                ->options(
                                    [
                                        ReportPeriodEnum::MONTHLY->value => __('Monthly'),
                                        ReportPeriodEnum::YEARLY->value => __('Yearly'),
                                    ]
                                )
                                ->selectablePlaceholder(false)
                                ->live(),
                            Select::make('month')
                                ->default(now()->month)
                                ->hidden(fn(Get $get) => $get('period') === ReportPeriodEnum::YEARLY->value || !$get('period'))
                                ->label(__('labels.month'))
                                ->options(
                                    function () {
                                        return collect(CarbonPeriod::create(now()->startOfYear(), '1 month', now()->endOfYear()))
                                            ->map(fn(Carbon $date) => $date->month)
                                            ->sortDesc()
                                            ->mapWithKeys(fn(int $month) => [$month => __('months.'.$month)]);
                                    }
                                )
                                ->selectablePlaceholder(false)
                                ->required(),
                            Select::make('year')
                                ->options(
                                    function () {
                                        return collect(CarbonPeriod::create(now()->subYears(10), '1 year', now()))
                                            ->map(fn(Carbon $date) => $date->year)
                                            ->sortDesc()
                                            ->mapWithKeys(fn(int $year) => [$year => $year]);
                                    }
                                )
                                ->default(now()->year)
                                ->selectablePlaceholder(false)
                                ->label(__('labels.year'))
                                ->required(),
                        ])
                        ->modifyBaseQueryUsing(function (Builder $query, array $data): Builder {
                            $periodEnum = ReportPeriodEnum::from($data['period']);

                            $date = match ($periodEnum) {
                                ReportPeriodEnum::MONTHLY => CarbonImmutable::create($data['year'], $data['month']),
                                ReportPeriodEnum::YEARLY => CarbonImmutable::create($data['year']),
                            };

                            $period = $periodEnum->getPeriod($date);

                            return $query->whereBetween('processes_banks.start_date', [
                                $period->getStartDate(),
                                $period->getEndDate(),
                            ]);
                        })
                ],
                layout: FiltersLayout::AboveContent
            )
            ->query($this->getTableQuery())
            ->columns([
                TextColumn::make('index')
                    ->label(__('labels.lp'))
                    ->state(
                        static function (HasTable $livewire, stdClass $rowLoop): string {
                            return (string)(
                                $rowLoop->iteration +
                                ($livewire->getTableRecordsPerPage() * (
                                        $livewire->getTablePage() - 1
                                    ))
                            );
                        }
                    ),
                
            ]);
    }

    protected function getTableQuery(): Builder|Relation|null
    {
        return $this->getReportRepository()
            ->getBrokersResultsQuery($this->departmentId);
    }

    public function getReportRepository(): ReportRepositoryInterface
    {
        ray(['getReportRepository', $this->departmentId])->red();
        return app(ReportRepositoryInterface::class);
    }

    protected function getTableHeading(): string|Htmlable|null
    {
        return __('Best brokers');
    }
}

Everything work well in the first render of the page: enter image description here

But, when i change option in a select: enter image description here

I get old departmentId in Repository, but in listener i get correct: enter image description here

It seems like, event is called after getting data from the table, so $this->departmentId is old?

First run: 2166 -> changed to 2167 -> stil 2166 -> changed to 2166 -> i get previous id 2167

Upvotes: 0

Views: 89

Answers (0)

Related Questions