From aa23795b2b9a0bb04317ef4f0a43332e449a1524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20Ioni=C8=9B=C4=83?= Date: Fri, 4 Apr 2025 16:38:01 +0100 Subject: [PATCH 1/3] feat: make shelter attributes listable --- app/Models/ShelterAttribute.php | 9 +++++++++ .../factories/ShelterAttributeFactory.php | 1 + ...ted_column_to_shelter_attributes_table.php | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 database/migrations/0001_01_04_000009_add_is_listed_column_to_shelter_attributes_table.php diff --git a/app/Models/ShelterAttribute.php b/app/Models/ShelterAttribute.php index b1a733e..41d3794 100644 --- a/app/Models/ShelterAttribute.php +++ b/app/Models/ShelterAttribute.php @@ -26,6 +26,7 @@ class ShelterAttribute extends Model 'name', 'type', 'is_enabled', + 'is_listed', ]; public array $translatable = [ @@ -37,6 +38,7 @@ public function casts(): array return [ 'type' => AttributeType::class, 'is_enabled' => 'boolean', + 'is_listed' => 'boolean', ]; } @@ -58,4 +60,11 @@ public function scopeWhereAttribute(Builder $query): Builder { return $query->where('type', AttributeType::ATTRIBUTE); } + + public function scopeWhereListed(Builder $query): Builder + { + return $query + ->where('is_enabled', true) + ->where('is_listed', true); + } } diff --git a/database/factories/ShelterAttributeFactory.php b/database/factories/ShelterAttributeFactory.php index b0fbed8..494605e 100644 --- a/database/factories/ShelterAttributeFactory.php +++ b/database/factories/ShelterAttributeFactory.php @@ -25,6 +25,7 @@ public function definition(): array 'name' => fake()->word(), 'is_enabled' => true, 'type' => AttributeType::ATTRIBUTE, + 'is_listed' => fake()->boolean(), ]; } diff --git a/database/migrations/0001_01_04_000009_add_is_listed_column_to_shelter_attributes_table.php b/database/migrations/0001_01_04_000009_add_is_listed_column_to_shelter_attributes_table.php new file mode 100644 index 0000000..c625249 --- /dev/null +++ b/database/migrations/0001_01_04_000009_add_is_listed_column_to_shelter_attributes_table.php @@ -0,0 +1,19 @@ +boolean('is_listed') + ->default(false) + ->after('is_enabled'); + }); + } +}; From a943210e2c7934438e10a66bfb94b0fbd40968fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20Ioni=C8=9B=C4=83?= Date: Tue, 8 Apr 2025 15:27:44 +0100 Subject: [PATCH 2/3] wip --- app/Forms/Components/RadioCard.php | 15 ++++ app/Livewire/RequestPage.php | 67 +++++++++++++++-- app/Models/Request.php | 4 +- app/Models/Shelter.php | 15 ++++ lang/en/app.php | 4 + .../forms/components/radio-card.blade.php | 73 +++++++++++++++++++ .../shelter-radio-card-content.blade.php | 22 ++++++ 7 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 app/Forms/Components/RadioCard.php create mode 100644 resources/views/forms/components/radio-card.blade.php create mode 100644 resources/views/forms/components/shelter-radio-card-content.blade.php diff --git a/app/Forms/Components/RadioCard.php b/app/Forms/Components/RadioCard.php new file mode 100644 index 0000000..d180023 --- /dev/null +++ b/app/Forms/Components/RadioCard.php @@ -0,0 +1,15 @@ +whereListed() - ->get(['id', 'name', 'address']); + ->with('shelterVariables') + ->when( + data_get($this->data, 'filters.variables'), + fn (Builder $query, array $variables) => $query->whereHasShelterVariables($variables) + ) + ->when( + data_get($this->data, 'filters.locations'), + fn (Builder $query, array $locations) => $query->whereIn('location_id', $locations) + ) + ->get(); + + $attributes = ShelterAttribute::query() + ->with('shelterVariables') + ->whereListed() + ->get(); return $form ->schema([ @@ -102,7 +121,6 @@ public function form(Form $form): Form Checkbox::make('for_group') ->label(__('app.field.request_group')) ->live(), - ]), Section::make(__('app.field.requester')) @@ -169,13 +187,51 @@ public function form(Form $form): Form Section::make(__('app.field.request_shelter')) ->schema([ - Radio::make('shelter_id') + Grid::make() + ->statePath('filters') + ->schema([ + Select::make('locations') + ->label(__('app.field.location')) + ->options( + Location::query() + ->whereHas('shelters') + ->get() + ->pluck('name', 'id') + ) + ->searchable() + ->multiple() + ->lazy(), + + ...$attributes->map( + fn (ShelterAttribute $shelterAttribute) => Select::make("variables.{$shelterAttribute->id}") + ->label($shelterAttribute->name) + ->options($shelterAttribute->shelterVariables->pluck('name', 'id')) + ->searchable() + ->multiple() + ->lazy(), + )->all(), + ]), + + RadioCard::make('shelter_id') ->label(__('app.field.request_shelter')) ->columns() ->hiddenLabel() ->options($shelters->mapWithKeys(fn (Shelter $shelter) => [$shelter->id => $shelter->name])) - ->descriptions($shelters->mapWithKeys(fn (Shelter $shelter) => [$shelter->id => $shelter->address])) + ->descriptions($shelters->mapWithKeys(fn (Shelter $shelter) => [ + $shelter->id => view('forms.components.shelter-radio-card-content', [ + 'shelter' => $shelter, + 'attributes' => $attributes, + ]), + ])) ->required(), + + View::make('filament-tables::components.empty-state.index') + ->visible($shelters->isEmpty()) + ->viewData([ + 'icon' => 'heroicon-o-magnifying-glass', + 'heading' => __('app.shelter.empty_state.header'), + 'description' => __('app.shelter.empty_state.description'), + ]), ]), Section::make(__('app.field.group')) @@ -217,6 +273,7 @@ public function form(Form $form): Form ->schema([ DatePicker::make('start_date') ->label(__('app.field.start_date')) + ->afterOrEqual('today') ->required(), DatePicker::make('end_date') diff --git a/app/Models/Request.php b/app/Models/Request.php index bc9a5bb..aacf0fa 100644 --- a/app/Models/Request.php +++ b/app/Models/Request.php @@ -143,7 +143,7 @@ public static function typesenseModelSettings(): array ], [ 'name' => 'shelter_id', - 'type' => 'int64', + 'type' => 'string', 'optional' => true, ], [ @@ -163,7 +163,7 @@ public function toSearchableArray(): array return [ 'id' => (string) $this->id, 'searchable_id' => (string) $this->id, - 'shelter_id' => $this->shelter_id, + 'shelter_id' => (string) $this->shelter_id, 'beneficiary_name' => $this->beneficiary->name, ]; } diff --git a/app/Models/Shelter.php b/app/Models/Shelter.php index f82a933..32569c0 100644 --- a/app/Models/Shelter.php +++ b/app/Models/Shelter.php @@ -87,6 +87,21 @@ public function scopeWhereListed(Builder $query): Builder }); } + public function scopeWhereHasShelterVariables(Builder $query, array $variables): Builder + { + $variables = collect($variables) + ->filter(fn (array $value) => filled($value)); + + if ($variables->isEmpty()) { + return $query; + } + + return $query + ->whereHas('shelterVariables', function (Builder $query) use ($variables) { + $variables->each(fn (array $values) => $query->whereIn('shelter_variables.id', $values)); + }); + } + public function availableCapacity(): Attribute { return Attribute::make( diff --git a/lang/en/app.php b/lang/en/app.php index 89fb822..68e5bee 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -277,6 +277,10 @@ ], ], ], + 'empty_state' => [ + 'header' => 'No shelter found', + 'description' => 'Please try again with a different filter.', + ], ], 'user' => [ 'label' => [ diff --git a/resources/views/forms/components/radio-card.blade.php b/resources/views/forms/components/radio-card.blade.php new file mode 100644 index 0000000..d3d6aef --- /dev/null +++ b/resources/views/forms/components/radio-card.blade.php @@ -0,0 +1,73 @@ +@php + $gridDirection = $getGridDirection() ?? 'column'; + $id = $getId(); + $isDisabled = $isDisabled(); + $isInline = $isInline(); + $statePath = $getStatePath(); +@endphp + + + + @foreach ($getOptions() as $value => $label) + + @endforeach + + diff --git a/resources/views/forms/components/shelter-radio-card-content.blade.php b/resources/views/forms/components/shelter-radio-card-content.blade.php new file mode 100644 index 0000000..3dda1ef --- /dev/null +++ b/resources/views/forms/components/shelter-radio-card-content.blade.php @@ -0,0 +1,22 @@ +
+ {{ $shelter->address }} +
+ +
+ @foreach ($attributes as $attribute) + @php + $variables = $shelter->shelterVariables->where('shelter_attribute_id', $attribute->id)->pluck('name'); + @endphp + + @continue($variables->isEmpty()) + +
+
+ {{ $attribute->name }} +
+
+ {{ $variables->join(', ') }} +
+
+ @endforeach +
From 6994c12645819077e41193e1c4b425a059033ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20Ioni=C8=9B=C4=83?= Date: Tue, 8 Apr 2025 15:40:17 +0100 Subject: [PATCH 3/3] wip --- .../Widgets/ReferToShelterWidget.php | 13 +++++++++++++ app/Livewire/RequestPage.php | 1 + 2 files changed, 14 insertions(+) diff --git a/app/Filament/Shelter/Resources/RequestResource/Widgets/ReferToShelterWidget.php b/app/Filament/Shelter/Resources/RequestResource/Widgets/ReferToShelterWidget.php index 7e3f8cf..7fb714e 100644 --- a/app/Filament/Shelter/Resources/RequestResource/Widgets/ReferToShelterWidget.php +++ b/app/Filament/Shelter/Resources/RequestResource/Widgets/ReferToShelterWidget.php @@ -19,6 +19,7 @@ use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Table; use Filament\Widgets\TableWidget as BaseWidget; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Collection; use Illuminate\Support\HtmlString; @@ -30,6 +31,10 @@ class ReferToShelterWidget extends BaseWidget public function table(Table $table): Table { + $attributes = ShelterAttribute::query() + ->with('shelterVariables') + ->get(); + return $table ->query( fn () => Shelter::query() @@ -76,6 +81,14 @@ public function table(Table $table): Table SelectFilter::make('location') ->relationship('location', 'name'), + ...$attributes->map( + fn (ShelterAttribute $shelterAttribute) => SelectFilter::make("attribute.{$shelterAttribute->id}") + ->query(fn (Builder $query, array $state) => $query->whereHasShelterVariables($state)) + ->options($shelterAttribute->shelterVariables->pluck('name', 'id')) + ->label($shelterAttribute->name) + ->multiple() + ), + ], FiltersLayout::AboveContent) ->paginated(false); } diff --git a/app/Livewire/RequestPage.php b/app/Livewire/RequestPage.php index 034f376..0d91d38 100644 --- a/app/Livewire/RequestPage.php +++ b/app/Livewire/RequestPage.php @@ -189,6 +189,7 @@ public function form(Form $form): Form ->schema([ Grid::make() ->statePath('filters') + ->columns(3) ->schema([ Select::make('locations') ->label(__('app.field.location'))