modal refactor
This commit is contained in:
parent
121c57d3ee
commit
92351c0bc1
|
@ -6,45 +6,28 @@ use Livewire\Component;
|
||||||
|
|
||||||
class Table extends Component
|
class Table extends Component
|
||||||
{
|
{
|
||||||
public $columns = [];
|
// Table Configuration
|
||||||
public $rows = [];
|
public $columns = []; // Columns to display
|
||||||
public $selected = [];
|
public $rows = []; // Data rows for the table
|
||||||
public $addRoute = null;
|
public $selected = []; // Selected row IDs
|
||||||
public $hasAddButton = true;
|
public $addRoute = null; // Route for adding new rows (optional)
|
||||||
public $selectAll = false;
|
public $hasAddButton = true; // Whether the 'Add' button is shown
|
||||||
public $hasCheckbox = true;
|
public $selectAll = false; // Whether 'Select All' is active
|
||||||
public $hasActions = false;
|
public $hasCheckbox = true; // Whether checkboxes are shown for row selection
|
||||||
public $isViewPage = false;
|
public $hasActions = false; // Whether action buttons (like Edit/Delete) are shown
|
||||||
public $search = '';
|
public $isViewPage = false; // Whether the table is for a view page
|
||||||
public $sortField = null; // Column to sort
|
public $search = ''; // Search query for filtering rows
|
||||||
public $sortDirection = 'asc'; // Default sort direction
|
public $sortField = null; // Column to sort by
|
||||||
|
public $sortDirection = 'asc'; // Sorting direction (asc or desc)
|
||||||
|
|
||||||
// Inside App\Livewire\Components\Table
|
// Modal Configuration
|
||||||
|
public $showModal = false; // Whether the modal is visible
|
||||||
public $showModal = false;
|
public $modalMode = 'view'; // Modal mode: 'view' or 'edit'
|
||||||
public $modalMode = 'view'; // or 'edit'
|
public $modalData = []; // Data for the modal
|
||||||
public $modalData = [];
|
|
||||||
|
|
||||||
public function viewRow($id)
|
|
||||||
{
|
|
||||||
$this->modalData = collect($this->rows)->firstWhere('id', $id) ?? [];
|
|
||||||
$this->modalMode = 'view';
|
|
||||||
$this->showModal = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function editRow($id)
|
|
||||||
{
|
|
||||||
$this->modalData = collect($this->rows)->firstWhere('id', $id) ?? [];
|
|
||||||
$this->modalMode = 'edit';
|
|
||||||
$this->showModal = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function closeModal()
|
|
||||||
{
|
|
||||||
$this->showModal = false;
|
|
||||||
$this->modalData = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the table with given columns and rows
|
||||||
|
*/
|
||||||
public function mount($columns, $rows, $addRoute = null)
|
public function mount($columns, $rows, $addRoute = null)
|
||||||
{
|
{
|
||||||
$this->columns = $columns;
|
$this->columns = $columns;
|
||||||
|
@ -52,13 +35,46 @@ public function closeModal()
|
||||||
$this->addRoute = $addRoute;
|
$this->addRoute = $addRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update rows based on search
|
/**
|
||||||
|
* View a row's details in the modal
|
||||||
|
*/
|
||||||
|
public function viewRow($id)
|
||||||
|
{
|
||||||
|
$this->modalData = collect($this->rows)->firstWhere('id', $id) ?? [];
|
||||||
|
$this->modalMode = 'view';
|
||||||
|
$this->showModal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit a row's details in the modal
|
||||||
|
*/
|
||||||
|
public function editRow($id)
|
||||||
|
{
|
||||||
|
$this->modalData = collect($this->rows)->firstWhere('id', $id) ?? [];
|
||||||
|
$this->modalMode = 'edit';
|
||||||
|
$this->showModal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the modal
|
||||||
|
*/
|
||||||
|
public function closeModal()
|
||||||
|
{
|
||||||
|
$this->showModal = false;
|
||||||
|
$this->modalData = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the selected rows based on search input
|
||||||
|
*/
|
||||||
public function updatedSearch()
|
public function updatedSearch()
|
||||||
{
|
{
|
||||||
$this->selected = [];
|
$this->selected = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select all rows
|
/**
|
||||||
|
* Select or deselect all rows
|
||||||
|
*/
|
||||||
public function selectAllRows()
|
public function selectAllRows()
|
||||||
{
|
{
|
||||||
if ($this->selectAll) {
|
if ($this->selectAll) {
|
||||||
|
@ -68,7 +84,9 @@ public function closeModal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select single row
|
/**
|
||||||
|
* Select or deselect a single row
|
||||||
|
*/
|
||||||
public function selectRow($rowId)
|
public function selectRow($rowId)
|
||||||
{
|
{
|
||||||
if (in_array($rowId, $this->selected)) {
|
if (in_array($rowId, $this->selected)) {
|
||||||
|
@ -78,7 +96,9 @@ public function closeModal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sorting
|
/**
|
||||||
|
* Sort rows by a specific field
|
||||||
|
*/
|
||||||
public function sortBy($field)
|
public function sortBy($field)
|
||||||
{
|
{
|
||||||
if ($this->sortField === $field) {
|
if ($this->sortField === $field) {
|
||||||
|
@ -93,6 +113,9 @@ public function closeModal()
|
||||||
}, SORT_REGULAR, $this->sortDirection === 'desc')->values()->all(); // Use all() to return plain array again
|
}, SORT_REGULAR, $this->sortDirection === 'desc')->values()->all(); // Use all() to return plain array again
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the table view
|
||||||
|
*/
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.components.table', [
|
return view('livewire.components.table', [
|
||||||
|
|
|
@ -1,127 +1,146 @@
|
||||||
<div class="mt-10">
|
<div class="mt-10">
|
||||||
<div class="p-4 bg-white shadow-md">
|
<div class="p-4 bg-white shadow-md">
|
||||||
|
|
||||||
<!-- Top Bar with Search & Add Button -->
|
<!-- Top Bar with Search & Add Button -->
|
||||||
<div class="mb-4 flex items-center justify-between">
|
<div class="mb-4 flex items-center justify-between">
|
||||||
|
<!-- Search Input -->
|
||||||
<input type="text" wire:model.debounce.500ms="search"
|
<input type="text" wire:model.debounce.500ms="search"
|
||||||
class="w-80 p-2 border border-gray-300 rounded-md"
|
class="w-80 p-2 border border-gray-300 rounded-md"
|
||||||
placeholder="Search..."
|
placeholder="Search..."
|
||||||
autofocus>
|
autofocus>
|
||||||
|
|
||||||
|
<!-- Add Button (if enabled and route exists) -->
|
||||||
@if ($hasAddButton && $addRoute)
|
@if ($hasAddButton && $addRoute)
|
||||||
<a href="{{ $addRoute }}" wire:navigate
|
<a href="{{ $addRoute }}" wire:navigate
|
||||||
class="ml-4 px-4 py-2 bg-orange-500 text-white rounded-md hover:bg-orange-600">
|
class="ml-4 px-4 py-2 bg-orange-500 text-white rounded-md hover:bg-orange-600">
|
||||||
+ Add
|
+ Add
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Table Header -->
|
||||||
<table class="table-auto w-full">
|
<table class="table-auto w-full">
|
||||||
<thead class="bg-gray-100">
|
<thead class="bg-gray-100">
|
||||||
<tr>
|
<tr>
|
||||||
|
<!-- Checkbox for selecting rows (if enabled) -->
|
||||||
@if ($hasCheckbox)
|
@if ($hasCheckbox)
|
||||||
<th class="px-4 py-2 text-left">
|
<th class="px-4 py-2 text-left">
|
||||||
<input type="checkbox" wire:model="selectAll" wire:change="selectAllRows" class="cursor-pointer">
|
<input type="checkbox" wire:model="selectAll" wire:change="selectAllRows" class="cursor-pointer">
|
||||||
</th>
|
</th>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
<!-- Dynamic Columns (sortable) -->
|
||||||
@foreach ($columns as $column)
|
@foreach ($columns as $column)
|
||||||
<th class="px-4 py-2 text-left cursor-pointer" wire:click="sortBy('{{ $column['field'] }}')">
|
<th class="px-4 py-2 text-left cursor-pointer" wire:click="sortBy('{{ $column['field'] }}')">
|
||||||
{{ $column['label'] }}
|
{{ $column['label'] }}
|
||||||
@if ($sortField === $column['field'])
|
@if ($sortField === $column['field'])
|
||||||
@if ($sortDirection === 'asc')
|
@if ($sortDirection === 'asc')
|
||||||
<span class="ml-2">↑</span>
|
<span class="ml-2">↑</span>
|
||||||
@else
|
@else
|
||||||
<span class="ml-2">↓</span>
|
<span class="ml-2">↓</span>
|
||||||
@endif
|
@endif
|
||||||
@else
|
@else
|
||||||
<span class="ml-2">↕</span>
|
<span class="ml-2">↕</span>
|
||||||
@endif
|
@endif
|
||||||
</th>
|
</th>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
|
<!-- Actions Column (if enabled) -->
|
||||||
@if ($hasActions)
|
@if ($hasActions)
|
||||||
<th class="px-4 py-2 text-left">Actions</th>
|
<th class="px-4 py-2 text-left">Actions</th>
|
||||||
@endif
|
@endif
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
|
<!-- Table Body -->
|
||||||
<tbody>
|
<tbody>
|
||||||
@forelse ($rows as $row)
|
@forelse ($rows as $row)
|
||||||
<tr class="hover:bg-gray-50">
|
<tr class="hover:bg-gray-50">
|
||||||
@if ($hasCheckbox)
|
<!-- Checkbox for row selection (if enabled) -->
|
||||||
<td class="px-4 py-2">
|
@if ($hasCheckbox)
|
||||||
<input type="checkbox" wire:click="selectRow('{{ $row['id'] }}')"
|
<td class="px-4 py-2">
|
||||||
@if(in_array($row['id'], $selected)) checked @endif class="cursor-pointer">
|
<input type="checkbox" wire:click="selectRow('{{ $row['id'] }}')"
|
||||||
</td>
|
@if(in_array($row['id'], $selected)) checked @endif class="cursor-pointer">
|
||||||
@endif
|
</td>
|
||||||
|
|
||||||
@foreach ($columns as $column)
|
|
||||||
<td class="px-4 py-2">
|
|
||||||
{{ $row[$column['field']] ?? '' }}
|
|
||||||
</td>
|
|
||||||
@endforeach
|
|
||||||
|
|
||||||
@if ($hasActions)
|
|
||||||
<td class="px-4 py-2 gap-2 flex">
|
|
||||||
@if($isViewPage)
|
|
||||||
<button wire:click="viewRow({{ $row['id'] }})" class="text-gray-500 hover:text-gray-700">
|
|
||||||
<i class="fas fa-eye"></i>
|
|
||||||
</button>
|
|
||||||
@else
|
|
||||||
<button wire:click="editRow({{ $row['id'] }})" class="text-blue-500 hover:text-blue-700">
|
|
||||||
<i class="fas fa-edit"></i>
|
|
||||||
</button>
|
|
||||||
<button wire:click="viewRow({{ $row['id'] }})" class="text-gray-500 hover:text-gray-700">
|
|
||||||
<i class="fas fa-eye"></i>
|
|
||||||
</button>
|
|
||||||
<button wire:click="deleteRow({{ $row['id'] }})" class="text-red-500 hover:text-red-700">
|
|
||||||
<i class="fas fa-trash-alt"></i>
|
|
||||||
</button>
|
|
||||||
@endif
|
@endif
|
||||||
</td>
|
|
||||||
@endif
|
<!-- Display Data for each column -->
|
||||||
@if ($showModal)
|
@foreach ($columns as $column)
|
||||||
<div class="fixed inset-0 bg-gray-900 bg-opacity-50 flex items-center justify-center z-50">
|
<td class="px-4 py-2">
|
||||||
<div class="bg-white p-6 rounded-lg shadow-lg w-1/2">
|
{{ $row[$column['field']] ?? '' }}
|
||||||
<div class="flex justify-between items-center mb-4">
|
</td>
|
||||||
<h2 class="text-lg font-semibold">
|
@endforeach
|
||||||
{{ $modalMode === 'view' ? 'View Details' : 'Edit Details' }}
|
|
||||||
</h2>
|
<!-- Action Buttons (if enabled) -->
|
||||||
<button wire:click="closeModal" class="text-gray-600 hover:text-gray-800">×</button>
|
@if ($hasActions)
|
||||||
</div>
|
<td class="px-4 py-2 gap-2 flex">
|
||||||
<div class="space-y-4">
|
@if($isViewPage)
|
||||||
@foreach ($columns as $column)
|
<button wire:click="viewRow({{ $row['id'] }})" class="text-gray-500 hover:text-gray-700">
|
||||||
<div>
|
<i class="fas fa-eye"></i>
|
||||||
<label class="block text-sm font-medium text-gray-700">
|
</button>
|
||||||
{{ $column['label'] }}
|
@else
|
||||||
</label>
|
<button wire:click="editRow({{ $row['id'] }})" class="text-blue-500 hover:text-blue-700">
|
||||||
@if ($modalMode === 'edit')
|
<i class="fas fa-edit"></i>
|
||||||
<input type="text" wire:model.defer="modalData.{{ $column['field'] }}"
|
</button>
|
||||||
class="mt-1 p-2 border border-gray-300 rounded w-full">
|
<button wire:click="viewRow({{ $row['id'] }})" class="text-gray-500 hover:text-gray-700">
|
||||||
@else
|
<i class="fas fa-eye"></i>
|
||||||
<div class="mt-1 p-2 bg-gray-100 rounded">
|
</button>
|
||||||
{{ $modalData[$column['field']] ?? '' }}
|
<button wire:click="deleteRow({{ $row['id'] }})" class="text-red-500 hover:text-red-700">
|
||||||
</div>
|
<i class="fas fa-trash-alt"></i>
|
||||||
@endif
|
</button>
|
||||||
</div>
|
@endif
|
||||||
@endforeach
|
</td>
|
||||||
</div>
|
@endif
|
||||||
@if ($modalMode === 'edit')
|
</tr>
|
||||||
<div class="mt-6 flex justify-end">
|
|
||||||
<button wire:click="saveRow" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</tr>
|
|
||||||
@empty
|
@empty
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="{{ count($columns) + 1 }}" class="text-center p-4">No data available</td>
|
<td colspan="{{ count($columns) + 1 }}" class="text-center p-4">No data available</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforelse
|
@endforelse
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<!-- Modal for Viewing / Editing Row -->
|
||||||
|
@if ($showModal)
|
||||||
|
<div class="fixed inset-0 bg-gray-900 bg-opacity-50 flex items-center justify-center z-50">
|
||||||
|
<div class="bg-white p-6 rounded-lg shadow-lg w-1/2">
|
||||||
|
<!-- Modal Header -->
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<h2 class="text-lg font-semibold">
|
||||||
|
{{ $modalMode === 'view' ? 'View Details' : 'Edit Details' }}
|
||||||
|
</h2>
|
||||||
|
<button wire:click="closeModal" class="text-gray-600 hover:text-gray-800">×</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal Body -->
|
||||||
|
<div class="space-y-4">
|
||||||
|
@foreach ($columns as $column)
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700">
|
||||||
|
{{ $column['label'] }}
|
||||||
|
</label>
|
||||||
|
@if ($modalMode === 'edit')
|
||||||
|
<input type="text" wire:model.defer="modalData.{{ $column['field'] }}"
|
||||||
|
class="mt-1 p-2 border border-gray-300 rounded w-full">
|
||||||
|
@else
|
||||||
|
<div class="mt-1 p-2 bg-gray-100 rounded">
|
||||||
|
{{ $modalData[$column['field']] ?? '' }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal Footer with Save Button (if in edit mode) -->
|
||||||
|
@if ($modalMode === 'edit')
|
||||||
|
<div class="mt-6 flex justify-end">
|
||||||
|
<button wire:click="saveRow" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
Loading…
Reference in New Issue