Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions resources/views/editor.blade.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<div class="mb-4">

@if (! count($criteria))
<div class="flex justify-between items-center p-2 mb-4 text-sm font-medium leading-5
bg-white rounded-lg text-slate-400 shadow">
<div class="flex justify-between items-center p-2 mb-4 text-sm font-medium leading-5 bg-white rounded-lg text-slate-400 shadow">
<span wire:click="addCriteria"
class="flex items-center gap-1 text-gray-500 hover:text-flamingo-500 text-sm cursor-pointer"><x-tabler-plus
class="w-4 h-auto"/> Add a new condition</span>
Expand Down
11 changes: 11 additions & 0 deletions resources/views/filters.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div class="p-4 px-6 grid grid-cols-3 gap-6 text-sm">
@foreach($this->filters() as $filter)
@include('query-builder::filters.' . $filter->component())
@endforeach
</div>
<div class="p-2 flex items-center justify-end gap-2 bg-gray-50 text-sm rounded-b border-t border-t-gray-200">
<button wire:click="resetFilters" class="flex items-center gap-2 text-gray-500 hover:text-red-500">
<x-tabler-trash class="w-4 h-auto" />
Reset
</button>
</div>
8 changes: 8 additions & 0 deletions resources/views/filters/boolean.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div>
<label for="filter-{{ $filter->code() }}" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{ $filter->label() }}</label>
<select wire:model="filterValues.{{ $filter->code() }}" id="filter-{{ $filter->code() }}" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
<option value="">Choose an option</option>
<option value="1">Yes</option>
<option value="0">No</option>
</select>
</div>
10 changes: 10 additions & 0 deletions resources/views/filters/date.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div>
<label for="filter-{{ $filter->code() }}" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{ $filter->label() }}</label>
<input type="date"
wire:model.lazy="filterValues.{{ $filter->code() }}"
wire:key="filter-{{ $filter->code() }}"
id="filter-{{ $filter->code() }}"
class="w-full bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
/>
</div>

11 changes: 11 additions & 0 deletions resources/views/filters/select.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div>
<label for="filter-{{ $filter->code() }}"
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{ $filter->label() }}</label>
<select wire:model="filterValues.{{ $filter->code() }}" id="filter-{{ $filter->code() }}"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
<option value="">Choose an option</option>
@foreach($filter->options() as $key => $value)
<option value="{{ $key }}">{{ $value }}</option>
@endforeach
</select>
</div>
4 changes: 4 additions & 0 deletions resources/views/filters/text.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div>
<label for="text-{{ $filter->code() }}" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{ $filter->label() }}</label>
<input wire:model.debounce.500ms="filterValues.{{ $filter->code() }}" type="text" id="text-{{ $filter->code() }}" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
</div>
92 changes: 92 additions & 0 deletions resources/views/table.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<div class="my-6">

<div>
@if ($this->areFiltersAvailable())
<div class="m-2 mb-4 bg-white rounded shadow">
@include('query-builder::filters')
</div>
@endif
</div>

<div>
@if($this->rows->count())

<div class="relative overflow-x-auto">
<table class="w-full text-sm text-left text-gray-500">
<thead class="text-xs text-gray-700 uppercase bg-gray-50">
<tr class="border-y border-gray-200">

@foreach ($this->columns() as $column)
<th @if ($column->isSortable()) wire:click="sort('{{ $column->key }}')" @endif>
@if ($column->showHeader)
<div @class([
'flex items-center gap-1 bg-gray-50 px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500 ' . $column->justify,
'cursor-pointer' => $column->isSortable(),
])>
{{ $column->label }}

@if ($sortBy === $column->key)
@if ($sortDirection === 'asc')
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5"
viewBox="0 0 20 20"
fill="currentColor">
<path fill-rule="evenodd"
d="M14.707 10.293a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L9 12.586V5a1 1 0 012 0v7.586l2.293-2.293a1 1 0 011.414 0z"
clip-rule="evenodd"/>
</svg>
@else
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5"
viewBox="0 0 20 20"
fill="currentColor">
<path fill-rule="evenodd"
d="M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L11 7.414V15a1 1 0 11-2 0V7.414L6.707 9.707a1 1 0 01-1.414 0z"
clip-rule="evenodd"/>
</svg>
@endif
@endif

</div>
@endif
</th>
@endforeach
</tr>
</thead>
<tbody wire:loading.class="opacity-50">

@foreach ($this->rows as $row)
<tr @if($this->isClickable())
wire:click="rowClick('{{ $row->id }}')"
@endif
wire:key="row-{{ $row->id }}"
@class([
'bg-white border-b',
'hover:bg-gray-50 cursor-pointer' => $this->isClickable(),
])>

@foreach ($this->columns() as $column)
<td>
<div class="py-3 px-6 flex items-center">
<x-dynamic-component
:component="$column->component"
:value="$column->getValue($row)"
:column="$column"
:row="$row"
>
</x-dynamic-component>
</div>
</td>
@endforeach
</tr>
@endforeach
</tbody>
</table>
</div>

@if($this->rows->hasPages())
<div class="border-b border-gray-200 shadow-sm">
<div class="py-2 px-6">{{ $this->rows->links() }}</div>
</div>
@endif
@endif
</div>
</div>
52 changes: 52 additions & 0 deletions src/Http/Livewire/QueryBuilder/Concerns/WithFilters.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns;

use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters\BooleanFilter;
use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters\DateFilter;
use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters\SelectFilter;
use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters\TextFilter;

trait WithFilters
{
protected $displayFilters = false;

public $filterValues = [];

public function areFiltersAvailable(): bool
{
return $this->displayFilters && count($this->filters()) > 0;
}

public function displayFilters(bool $displayFilters = true): static
{
$this->displayFilters = $displayFilters;

return $this;
}

public function filters(): array
{
return [
TextFilter::make('Name', 'full_name')->useOperator('like'),
SelectFilter::make('Location', 'contract.location.name')->withOptions([
'ACT Skills Centre, Caerphilly' => 'ACT Skills Centre, Caerphilly',
'Home Based' => 'Home Based',
]),
BooleanFilter::make('Line Manager', 'contract.line_manager'),
DateFilter::make('Started on or after', 'contract.start_date')->useOperator('>='),
DateFilter::make('Started on or before', 'contract.start_date')->useOperator('<='),
];
}

public function resetFilters(): void
{
$this->filterValues = [];
$this->resetPage();
}

public function updatedFilterValues(): void
{
$this->resetPage();
}
}
2 changes: 1 addition & 1 deletion src/Http/Livewire/QueryBuilder/Concerns/WithPagination.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ trait WithPagination
public function applyPagination($query)
{
if ($this->paginate) {
return $query->paginate($this->perPage);
return $query->ray()->paginate($this->perPage);
} else {
return $query->get();
}
Expand Down
80 changes: 80 additions & 0 deletions src/Http/Livewire/QueryBuilder/Filters/BaseFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

namespace ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters;

use Illuminate\Support\Str;

/** @phpstan-consistent-constructor */
class BaseFilter
{
public string $key;

public string $label;

public string $operator = '=';

public string $code = '';

public string $component = 'text';

public function __construct($key, $label)
{
$this->key = $key;
$this->label = $label;
$this->code = $label.':'.$this->operator;
}

public static function make($label, $key = null): static
{
if (is_null($key)) {
$key = Str::snake($label);
}

return new static($key, $label);
}

public function label(): string
{
return $this->label;
}

public function key(): string
{
return $this->key;
}

public function operator(): string
{
return $this->operator;
}

public function code(): string
{
return $this->code;
}

public function component(): string
{
return $this->component;
}

public function useOperator(string $operator): static
{
$this->operator = $operator;
$this->code = $this->label.':'.$this->operator;

return $this;
}

public function useComponent(string $component): static
{
$this->component = $component;

return $this;
}

public function parseValue($value)
{
return $value;
}
}
21 changes: 21 additions & 0 deletions src/Http/Livewire/QueryBuilder/Filters/BooleanFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters;

class BooleanFilter extends BaseFilter
{
public string $component = 'boolean';

public function parseValue($value)
{
if (is_null($value) || $value === '') {
return null;
}

if (is_string($value)) {
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
}

return $value;
}
}
15 changes: 15 additions & 0 deletions src/Http/Livewire/QueryBuilder/Filters/DateFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters;

use Carbon\Carbon;

class DateFilter extends BaseFilter
{
public string $component = 'date';

public function parseValue($value)
{
return Carbon::parse($value)->startOfDay();
}
}
7 changes: 7 additions & 0 deletions src/Http/Livewire/QueryBuilder/Filters/NumberFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters;

class NumberFilter extends BaseFilter
{
}
22 changes: 22 additions & 0 deletions src/Http/Livewire/QueryBuilder/Filters/SelectFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters;

class SelectFilter extends BaseFilter
{
public $options = [];

public string $component = 'select';

public function options()
{
return $this->options;
}

public function withOptions(array $options = []): static
{
$this->options = $options;

return $this;
}
}
15 changes: 15 additions & 0 deletions src/Http/Livewire/QueryBuilder/Filters/TextFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Filters;

class TextFilter extends BaseFilter
{
public function parseValue($value)
{
if ($this->operator() === 'like') {
return "%{$value}%";
}

return $value;
}
}
2 changes: 2 additions & 0 deletions src/QueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithActions;
use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithCaching;
use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithColumns;
use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithFilters;
use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithPagination;
use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithQueryBuilder;
use ACTTraining\QueryBuilder\Http\Livewire\QueryBuilder\Concerns\WithRowClick;
Expand All @@ -28,6 +29,7 @@ abstract class QueryBuilder extends Component
use WithActions;
use WithCaching;
use WithColumns;
use WithFilters;
use WithPagination;
use WithQueryBuilder;
use WithRowClick;
Expand Down
Loading